library(swimplot) library(grid) library(gtable) library(readr) library(mosaic) library(dplyr) library(survival) library(survminer) library(ggplot2) library(scales) library(coxphf) library(ggthemes) library(tidyverse) library(gtsummary) library(flextable) library(parameters) library(car) library(ComplexHeatmap) library(tidyverse) library(readxl) library(janitor) library(DT) library(pROC) library(rms)

#ctDNA Detection Rates by Window and Stages

#ctDNA at Baseline
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data$ctDNA.Base <- factor(circ_data$ctDNA.Base, levels=c("NEGATIVE","POSITIVE"))
circ_data <- subset(circ_data, ctDNA.Base %in% c("NEGATIVE", "POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("O","I","II","III","IV"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.Base == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.Base, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.Base == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA post-treatment
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.postTx!="",]
circ_data$ctDNA.postTx <- factor(circ_data$ctDNA.postTx, levels=c("NEGATIVE","POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("O","I","II","III","IV"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.postTx == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.postTx, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.postTx == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#Overview plot

setwd("~/Downloads") 
clinstage <- read.csv("EORTC ICI_OP.csv")
clinstage_df <- as.data.frame(clinstage)

# Creating the basic swimmer plot
oplot <- swimmer_plot(df=clinstage_df,
                      id='PatientName',
                      end='fu.diff.months',
                      fill='gray',
                      width=.01)

# Adding themes and scales
oplot <- oplot + theme(panel.border = element_blank())
oplot <- oplot + scale_y_continuous(breaks = seq(0, 48, by = 3))
oplot <- oplot + labs(x ="Patients", y="Months from Immunotherapy Start")

# Adding swimmer points
oplot_ev1 <- oplot + swimmer_points(df_points=clinstage_df,
                                    id='PatientName',
                                    time='date.diff.months',
                                    name_shape ='Event_type',
                                    name_col = 'Event',
                                    size=3.5,fill='black')
# Optionally uncomment and use col='darkgreen' if needed

# Adding shape manual scale
oplot_ev1.1 <- oplot_ev1 + ggplot2::scale_shape_manual(name="Event_type",
                                                       values=c(1,16,6,4),
                                                       breaks=c('ctDNA_neg','ctDNA_pos','Imaging','Death'))

# Display the plot
oplot_ev1.1

                                    oplot_ev2 <- oplot_ev1.1 + swimmer_lines(df_lines=clinstage_df,
                                                                             id='PatientName',
                                                                             start='Tx_start.months',
                                                                             end='Tx_end.months',
                                                                             name_col='Tx_type',
                                                                             size=3.5,
                                                                             name_alpha = 1.0)
                                    oplot_ev2 <- oplot_ev2 + guides(linetype = guide_legend(override.aes = list(size = 5, color = "black")))
                                    oplot_ev2

oplot_ev2.2 <- oplot_ev2 + ggplot2::scale_color_manual(name="Event",values=c( "orange", "black", "black", "lightblue", "green", "red"))
oplot_ev2.2

#Overview plot - stratified by BOR

setwd("~/Downloads") 
clinstage <- read.csv("EORTC ICI_OP.csv")
clinstage_df <- as.data.frame(clinstage)

# Creating the basic swimmer plot
oplot_stratify <-swimmer_plot(df=clinstage_df,
                              id='PatientName',
                              end='fu.diff.months',
                              col="gray",
                              alpha=0.75,
                              width=.01,
                              base_size = 14,
                              stratify= c('RECIST'))
oplot_stratify <- oplot_stratify + theme(panel.border = element_blank())
oplot_stratify <- oplot_stratify + scale_y_continuous(breaks = seq(0, 42, by = 3))
oplot_stratify <- oplot_stratify + labs(x ="Patients" , y="Months from Immunotherapy Start")

# Adding swimmer points
oplot_ev1 <- oplot_stratify + swimmer_points(df_points=clinstage_df,
                                    id='PatientName',
                                    time='date.diff.months',
                                    name_shape ='Event_type',
                                    name_col = 'Event',
                                    size=3.5,fill='black')
# Optionally uncomment and use col='darkgreen' if needed

# Adding shape manual scale
oplot_ev1.1 <- oplot_ev1 + ggplot2::scale_shape_manual(name="Event_type",
                                                       values=c(1,16,6,4),
                                                       breaks=c('ctDNA_neg','ctDNA_pos','Imaging','Death'))

# Display the plot
oplot_ev1.1

                                    oplot_ev2 <- oplot_ev1.1 + swimmer_lines(df_lines=clinstage_df,
                                                                             id='PatientName',
                                                                             start='Tx_start.months',
                                                                             end='Tx_end.months',
                                                                             name_col='Tx_type',
                                                                             size=3.5,
                                                                             name_alpha = 1.0)
                                    oplot_ev2 <- oplot_ev2 + guides(linetype = guide_legend(override.aes = list(size = 5, color = "black")))
                                    oplot_ev2

oplot_ev2.2 <- oplot_ev2 + ggplot2::scale_color_manual(name="Event",values=c( "orange", "black", "black", "lightblue", "green", "red"))
oplot_ev2.2

#Association of Baseline ctDNA MTM levels with clinicopathological factors

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_datadf <- as.data.frame(circ_data)

tally(~cStage, data=circ_data, margins = TRUE)
cStage
  0-II III-IV  Total 
     7     22     29 
circ_data$cStage <- factor(circ_data$cStage, levels = c("0-II","III-IV"), labels = c("0-II (n=7)","III-IV (n=22)"))
boxplot(ctDNA.Base.MTM~cStage, data=circ_data, main="ctDNA pre-treatment MTM - Stage", xlab="Stage", ylab="MTM/mL", col="white",border="black")

m1<-wilcox.test(ctDNA.Base.MTM ~ cStage, data=circ_data, na.rm=TRUE, exact=FALSE, conf.int=TRUE)
print(m1)

    Wilcoxon rank sum test with continuity correction

data:  ctDNA.Base.MTM by cStage
W = 39.5, p-value = 0.05896
alternative hypothesis: true location shift is not equal to 0
95 percent confidence interval:
 -5.19000e+01  4.27605e-05
sample estimates:
difference in location 
             -6.799975 
tally(~Inclusion.status, data=circ_data, margins = TRUE)
Inclusion.status
Loco-regional    Metastatic         Total 
           18            11            29 
circ_data$Inclusion.status <- factor(circ_data$Inclusion.status, levels = c("Loco-regional","Metastatic"), labels = c("Loco-regional (n=18)","Metastatic (n=11)"))
boxplot(ctDNA.Base.MTM~Inclusion.status, data=circ_data, main="ctDNA pre-treatment MTM - Disease Status", xlab="Disease Status", ylab="MTM/mL", col="white",border="black")

m2<-wilcox.test(ctDNA.Base.MTM ~ Inclusion.status, data=circ_data, na.rm=TRUE, exact=FALSE, conf.int=TRUE)
print(m2)

    Wilcoxon rank sum test with continuity correction

data:  ctDNA.Base.MTM by Inclusion.status
W = 93.5, p-value = 0.8219
alternative hypothesis: true location shift is not equal to 0
95 percent confidence interval:
 -8.399949  6.899953
sample estimates:
difference in location 
            -0.3727674 
tally(~cT.Status, data=circ_data, margins = TRUE)
cT.Status
cT0-T2 cT3-T4    cTx  Total 
    11     17      1     29 
circ_data$cT.Status <- factor(circ_data$cT.Status, levels = c("cT0-T2","cT3-T4"), labels = c("cT0-T2 (n=11)","cT3-T4 (n=17)"))
boxplot(ctDNA.Base.MTM~cT.Status, data=circ_data, main="ctDNA pre-treatment MTM - cT status", xlab="cT status", ylab="MTM/mL", col="white",border="black")

m3<-wilcox.test(ctDNA.Base.MTM ~ cT.Status, data=circ_data, na.rm=TRUE, exact=FALSE, conf.int=TRUE)
print(m3)

    Wilcoxon rank sum test with continuity correction

data:  ctDNA.Base.MTM by cT.Status
W = 45.5, p-value = 0.02523
alternative hypothesis: true location shift is not equal to 0
95 percent confidence interval:
 -57.0000356  -0.7999756
sample estimates:
difference in location 
             -7.400021 
tally(~cN.Status, data=circ_data, margins = TRUE)
cN.Status
   cN0 cN1-N3    cNx  Total 
    12     15      2     29 
circ_data$cN.Status <- factor(circ_data$cN.Status, levels = c("cN0","cN1-N3"), labels = c("cN0 (n=12)","cN1-N3 (n=15)"))
boxplot(ctDNA.Base.MTM~cN.Status, data=circ_data, main="ctDNA pre-treatment MTM - cN status", xlab="cN status", ylab="MTM/mL", col="white",border="black")

m4<-wilcox.test(ctDNA.Base.MTM ~ cN.Status, data=circ_data, na.rm=TRUE, exact=FALSE, conf.int=TRUE)
print(m4)

    Wilcoxon rank sum test with continuity correction

data:  ctDNA.Base.MTM by cN.Status
W = 32.5, p-value = 0.005379
alternative hypothesis: true location shift is not equal to 0
95 percent confidence interval:
 -60.200006  -3.299997
sample estimates:
difference in location 
             -10.15193 
tally(~p16.status, data=circ_data, margins = TRUE)
p16.status
Negative Positive  Unknown    Total 
      24        4        1       29 
circ_data$p16.status <- factor(circ_data$p16.status, levels = c("Negative","Positive"), labels = c("p16 neg (n=24)","p16 pos (n=4)"))
boxplot(ctDNA.Base.MTM~p16.status, data=circ_data, main="ctDNA pre-treatment MTM - p16 status", xlab="p16 status", ylab="MTM/mL", col="white",border="black")

m5<-wilcox.test(ctDNA.Base.MTM ~ p16.status, data=circ_data, na.rm=TRUE, exact=FALSE, conf.int=TRUE)
print(m5)

    Wilcoxon rank sum test with continuity correction

data:  ctDNA.Base.MTM by p16.status
W = 55.5, p-value = 0.6453
alternative hypothesis: true location shift is not equal to 0
95 percent confidence interval:
 -47.89994  46.29998
sample estimates:
difference in location 
             0.8901786 

#Median MTM/mL levels for ctDNA positive pts pre-treatment

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]

median_ctDNA <- median(circ_data$ctDNA.Base.MTM, na.rm = TRUE)
range_ctDNA <- range(circ_data$ctDNA.Base.MTM, na.rm = TRUE)
cat("Median MTM/mL post-treatment:", median_ctDNA, "\n")
Median MTM/mL post-treatment: 8.4 
cat("Range MTM/mL post-treatment:", range_ctDNA[1], "-", range_ctDNA[2], "\n")
Range MTM/mL post-treatment: 0.2 - 986 

#Median MTM/mL levels for ctDNA positive pts post-treatment

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.postTx!="",]
circ_data <- circ_data[circ_data$ctDNA.postTx=="POSITIVE",]

median_ctDNA <- median(circ_data$ctDNA.postTx.MTM, na.rm = TRUE)
range_ctDNA <- range(circ_data$ctDNA.postTx.MTM, na.rm = TRUE)
cat("Median MTM/mL post-treatment:", median_ctDNA, "\n")
Median MTM/mL post-treatment: 7.9 
cat("Range MTM/mL post-treatment:", range_ctDNA[1], "-", range_ctDNA[2], "\n")
Range MTM/mL post-treatment: 0.1 - 737.8 

#Median time from end treatment to progression for ctDNA negative pts post-treatment

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.postTx!="",]
circ_data <- circ_data[circ_data$ctDNA.postTx=="NEGATIVE",]
circ_data <- circ_data[circ_data$PFS.Event=="TRUE",]

median_PFS <- median(circ_data$PFS.months, na.rm = TRUE)
range_PFS <- range(circ_data$PFS.months, na.rm = TRUE)
cat("Median PFS:", median_PFS, "\n")
Median PFS: 4.977494 
cat("Range PFS:", range_PFS[1], "-", range_PFS[2], "\n")
Range PFS: 3.055492 - 19.67999 

#PFS by ctDNA status post/during-ICI

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.postTx!="",]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)~ctDNA.postTx, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event) ~ 
    ctDNA.postTx, data = circ_data)

                       n events median 0.95LCL 0.95UCL
ctDNA.postTx=NEGATIVE  9      4     NA    6.70      NA
ctDNA.postTx=POSITIVE 20     19   3.81    2.37    6.64
event_summary <- circ_data %>%
  group_by(ctDNA.postTx) %>%
  summarise(
    Total = n(),
    Events = sum(PFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.postTx, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="PFS - ctDNA Post/Under treatment", ylab= "Progression-Free Survival", xlab="Months from Start of Immunotherapy", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(0, 12, 24, 36))
Call: survfit(formula = surv_object ~ ctDNA.postTx, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.postTx=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0      9       0    1.000   0.000        1.000        1.000
   12      5       3    0.667   0.157        0.282        0.878
   24      3       1    0.533   0.173        0.177        0.796
   36      2       0    0.533   0.173        0.177        0.796

                ctDNA.postTx=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0     20       0     1.00  0.0000      1.00000        1.000
   12      2      18     0.10  0.0671      0.01698        0.272
   24      1       1     0.05  0.0487      0.00345        0.205
   36      1       0     0.05  0.0487      0.00345        0.205
circ_data$ctDNA.postTx <- factor(circ_data$ctDNA.postTx, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.postTx, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.postTx, data = circ_data)

  n= 29, number of events= 23 

                       coef exp(coef) se(coef)     z Pr(>|z|)   
ctDNA.postTxPOSITIVE 1.5616    4.7666   0.5703 2.738  0.00618 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                     exp(coef) exp(-coef) lower .95 upper .95
ctDNA.postTxPOSITIVE     4.767     0.2098     1.559     14.58

Concordance= 0.649  (se = 0.049 )
Likelihood ratio test= 9.7  on 1 df,   p=0.002
Wald test            = 7.5  on 1 df,   p=0.006
Score (logrank) test = 8.78  on 1 df,   p=0.003
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 4.77 (1.56-14.58); p = 0.006"
circ_data$ctDNA.postTx <- factor(circ_data$ctDNA.postTx, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$PFS.Event <- factor(circ_data$PFS.Event, levels = c("FALSE", "TRUE"), labels = c("No Progression", "Progression"))
contingency_table <- table(circ_data$ctDNA.postTx, circ_data$PFS.Event)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 6.8323, df = 1, p-value = 0.008952
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.005482
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
    1.68957 1169.09723
sample estimates:
odds ratio 
  20.33413 
print(contingency_table)
          
           No Progression Progression
  Negative              5           4
  Positive              1          19
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "ctDNA status post/under-treatment", 
       x = "ctDNA", 
       y = "Patients (%)", 
       fill = "Progression",
       caption = paste("Fisher's exact test p-value: ", format.pval(fisher_exact_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("No Progression" = "blue", "Progression" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Progression label size

#OS by ctDNA status post/during-ICI

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.postTx!="",]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$OS.months, event = circ_data$OS.Event)~ctDNA.postTx, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$OS.months, event = circ_data$OS.Event) ~ 
    ctDNA.postTx, data = circ_data)

                       n events median 0.95LCL 0.95UCL
ctDNA.postTx=NEGATIVE  9      4     NA   16.85      NA
ctDNA.postTx=POSITIVE 20     17   10.4    7.75      18
event_summary <- circ_data %>%
  group_by(ctDNA.postTx) %>%
  summarise(
    Total = n(),
    Events = sum(OS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$OS.months, event = circ_data$OS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.postTx, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="OS - ctDNA Post/Under treatment", ylab= "Overall Survival", xlab="Months from Start of Immunotherapy", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 24, 36))
Call: survfit(formula = surv_object ~ ctDNA.postTx, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.postTx=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      7       1    0.889   0.105        0.433        0.984
   24      3       3    0.508   0.177        0.157        0.781
   36      2       0    0.508   0.177        0.157        0.781

                ctDNA.postTx=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      9      11     0.45  0.1112       0.2311        0.647
   24      3       5     0.18  0.0900       0.0480        0.380
   36      2       1     0.12  0.0775       0.0213        0.311
circ_data$ctDNA.postTx <- factor(circ_data$ctDNA.postTx, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.postTx, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.postTx, data = circ_data)

  n= 29, number of events= 21 

                       coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.postTxPOSITIVE 1.2213    3.3918   0.5621 2.173   0.0298 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                     exp(coef) exp(-coef) lower .95 upper .95
ctDNA.postTxPOSITIVE     3.392     0.2948     1.127     10.21

Concordance= 0.638  (se = 0.048 )
Likelihood ratio test= 5.81  on 1 df,   p=0.02
Wald test            = 4.72  on 1 df,   p=0.03
Score (logrank) test = 5.29  on 1 df,   p=0.02
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 3.39 (1.13-10.21); p = 0.03"
circ_data$ctDNA.postTx <- factor(circ_data$ctDNA.postTx, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$OS.Event <- factor(circ_data$OS.Event, levels = c("FALSE", "TRUE"), labels = c("Alive", "Deceased"))
contingency_table <- table(circ_data$ctDNA.postTx, circ_data$OS.Event)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 3.2819, df = 1, p-value = 0.07005
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.0667
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  0.8624077 62.5051555
sample estimates:
odds ratio 
  6.505452 
print(contingency_table)
          
           Alive Deceased
  Negative     5        4
  Positive     3       17
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "ctDNA status post/under-treatment", 
       x = "ctDNA", 
       y = "Patients (%)", 
       fill = "Living Status",
       caption = paste("Fisher's exact test p-value: ", format.pval(fisher_exact_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Alive" = "blue", "Deceased" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Progression label size

#Association of ctDNA status post/during-ICI with BOR

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.postTx <- factor(circ_data$ctDNA.postTx, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$RESIST <- factor(circ_data$RESIST, levels = c("CR", "PR", "SD", "PD"))
contingency_table <- table(circ_data$ctDNA.postTx, circ_data$RESIST)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test

data:  contingency_table
X-squared = 11.869, df = 3, p-value = 0.007847
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.006541
alternative hypothesis: two.sided
print(contingency_table)
          
           CR PR SD PD
  Negative  4  3  0  2
  Positive  1  2  7 10
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "ctDNA status post/under-treatment", 
       x = "ctDNA", 
       y = "Patients (%)", 
       fill = "BOR",
       caption = paste("Fisher's exact test p-value: ", format.pval(fisher_exact_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("CR" = "blue", "PR" = "lightblue", "SD" = "orange", "PD" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Progression label size

#PFS by ctDNA kinetics post/during-ICI

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ΔctDNA!="",]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)~ΔctDNA, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event) ~ 
    ΔctDNA, data = circ_data)

                 n events median 0.95LCL 0.95UCL
ΔctDNA=NEGATIVE 13      8  18.04     6.7      NA
ΔctDNA=POSITIVE 12     12   2.41     2.3      NA
event_summary <- circ_data %>%
  group_by(ΔctDNA) %>%
  summarise(
    Total = n(),
    Events = sum(PFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
KM_curve <- survfit(surv_object ~ ΔctDNA, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="PFS - ctDNA Kinetics Post/Under treatment", ylab= "Progression-Free Survival", xlab="Months from Start of Immunotherapy", legend.labs=c("Decreased ΔctDNA", "Increased ΔctDNA"), legend.title="")

summary(KM_curve, times= c(0, 12, 24, 36))
Call: survfit(formula = surv_object ~ ΔctDNA, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ΔctDNA=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0     13       0    1.000   0.000        1.000        1.000
   12      6       6    0.538   0.138        0.248        0.760
   24      3       2    0.359   0.139        0.117        0.613
   36      2       0    0.359   0.139        0.117        0.613

                ΔctDNA=POSITIVE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
           0           12            0            1            0            1            1 
circ_data$ΔctDNA <- factor(circ_data$ΔctDNA, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ΔctDNA, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ΔctDNA, data = circ_data)

  n= 25, number of events= 20 

                 coef exp(coef) se(coef)    z Pr(>|z|)    
ΔctDNAPOSITIVE  2.716    15.112    0.794 3.42 0.000626 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

               exp(coef) exp(-coef) lower .95 upper .95
ΔctDNAPOSITIVE     15.11    0.06617     3.188     71.64

Concordance= 0.716  (se = 0.044 )
Likelihood ratio test= 17.9  on 1 df,   p=2e-05
Wald test            = 11.7  on 1 df,   p=6e-04
Score (logrank) test = 18.33  on 1 df,   p=2e-05
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 15.11 (3.19-71.64); p = 0.001"
circ_data$ΔctDNA <- factor(circ_data$ΔctDNA, levels = c("NEGATIVE", "POSITIVE"), labels = c("Decreased", "Increased"))
circ_data$PFS.Event <- factor(circ_data$PFS.Event, levels = c("FALSE", "TRUE"), labels = c("No Progression", "Progression"))
contingency_table <- table(circ_data$ΔctDNA, circ_data$PFS.Event)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 3.6158, df = 1, p-value = 0.05723
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.03913
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 1.013281      Inf
sample estimates:
odds ratio 
       Inf 
print(contingency_table)
           
            No Progression Progression
  Decreased              5           8
  Increased              0          12
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "ctDNA kinetics post/under-treatment", 
       x = "ctDNA", 
       y = "Patients (%)", 
       fill = "Progression",
       caption = paste("Fisher's exact test p-value: ", format.pval(fisher_exact_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("No Progression" = "blue", "Progression" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Progression label size

#OS by ctDNA kinetics post/during-ICI

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ΔctDNA!="",]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$OS.months, event = circ_data$OS.Event)~ΔctDNA, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$OS.months, event = circ_data$OS.Event) ~ 
    ΔctDNA, data = circ_data)

                 n events median 0.95LCL 0.95UCL
ΔctDNA=NEGATIVE 13      8   18.0    9.82      NA
ΔctDNA=POSITIVE 12     10   10.8    4.44      NA
event_summary <- circ_data %>%
  group_by(ΔctDNA) %>%
  summarise(
    Total = n(),
    Events = sum(OS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$OS.months, event = circ_data$OS.Event)
KM_curve <- survfit(surv_object ~ ΔctDNA, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="OS - ctDNA Kinetics Post/Under treatment", ylab= "Overall Survival", xlab="Months from Start of Immunotherapy", legend.labs=c("Decreased ΔctDNA", "Increased ΔctDNA"), legend.title="")

summary(KM_curve, times= c(0, 12, 24, 36))
Call: survfit(formula = surv_object ~ ΔctDNA, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ΔctDNA=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0     13       0    1.000   0.000        1.000        1.000
   12      7       5    0.615   0.135        0.308        0.818
   24      3       3    0.352   0.139        0.112        0.607
   36      2       0    0.352   0.139        0.112        0.607

                ΔctDNA=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0     12       0    1.000   0.000      1.00000        1.000
   12      6       6    0.500   0.144      0.20848        0.736
   24      2       3    0.222   0.128      0.04111        0.492
   36      1       1    0.111   0.101      0.00701        0.378
circ_data$ΔctDNA <- factor(circ_data$ΔctDNA, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ΔctDNA, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ΔctDNA, data = circ_data)

  n= 25, number of events= 18 

                 coef exp(coef) se(coef)     z Pr(>|z|)
ΔctDNAPOSITIVE 0.6947    2.0031   0.4806 1.445    0.148

               exp(coef) exp(-coef) lower .95 upper .95
ΔctDNAPOSITIVE     2.003     0.4992    0.7809     5.138

Concordance= 0.598  (se = 0.061 )
Likelihood ratio test= 2.1  on 1 df,   p=0.1
Wald test            = 2.09  on 1 df,   p=0.1
Score (logrank) test = 2.17  on 1 df,   p=0.1
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 2 (0.78-5.14); p = 0.148"
circ_data$ΔctDNA <- factor(circ_data$ΔctDNA, levels = c("NEGATIVE", "POSITIVE"), labels = c("Decreased", "Increased"))
circ_data$OS.Event <- factor(circ_data$OS.Event, levels = c("FALSE", "TRUE"), labels = c("Alive", "Deceased"))
contingency_table <- table(circ_data$ΔctDNA, circ_data$OS.Event)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 0.58792, df = 1, p-value = 0.4432
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.3783
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  0.363132 39.390335
sample estimates:
odds ratio 
  2.985191 
print(contingency_table)
           
            Alive Deceased
  Decreased     5        8
  Increased     2       10
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "ctDNA kinetics post/under-treatment", 
       x = "ctDNA", 
       y = "Patients (%)", 
       fill = "Vital Status",
       caption = paste("Fisher's exact test p-value: ", format.pval(fisher_exact_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Alive" = "blue", "Deceased" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Progression label size

#Association of ctDNA kinetics post/during-ICI with BOR

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ΔctDNA!="",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ΔctDNA <- factor(circ_data$ΔctDNA, levels = c("NEGATIVE", "POSITIVE"), labels = c("Decreased", "Increased"))
circ_data$RESIST <- factor(circ_data$RESIST, levels = c("CR", "PR", "SD", "PD"))
contingency_table <- table(circ_data$ΔctDNA, circ_data$RESIST)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test

data:  contingency_table
X-squared = 15.385, df = 3, p-value = 0.001516
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.0003154
alternative hypothesis: two.sided
print(contingency_table)
           
            CR PR SD PD
  Decreased  4  5  3  1
  Increased  0  0  3  9
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "ctDNA kinetics post/under-treatment", 
       x = "ctDNA", 
       y = "Patients (%)", 
       fill = "BOR",
       caption = paste("Fisher's exact test p-value: ", format.pval(fisher_exact_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("CR" = "blue", "PR" = "lightblue", "SD" = "orange", "PD" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Progression label size

#PFS by ctDNA clearance post/during-ICI

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "NEGATIVE" ~ 1,
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "POSITIVE" ~ 2
  ))

survfit(Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

                  n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1  6      2     NA   19.68      NA
ctDNA.Dynamics=2 19     18   3.68    2.37    7.95
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(PFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="PFS - ctDNA clearance Post/Under treatment", ylab= "Progression-Free Survival", xlab="Months from Start of Immunotherapy", legend.labs=c("Clearance", "No Clearance"), legend.title="")

summary(KM_curve, times= c(0, 12, 24, 36))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0      6       0    1.000   0.000        1.000        1.000
   12      4       1    0.833   0.152        0.273        0.975
   24      2       1    0.625   0.213        0.142        0.893
   36      1       0    0.625   0.213        0.142        0.893

                ctDNA.Dynamics=2 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0     19       0   1.0000  0.0000      1.00000        1.000
   12      2      17   0.1053  0.0704      0.01777        0.284
   24      1       1   0.0526  0.0512      0.00359        0.214
   36      1       0   0.0526  0.0512      0.00359        0.214
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 25, number of events= 20 

                            coef exp(coef) se(coef)     z Pr(>|z|)   
ctDNA.DynamicsNo Clearance 2.085     8.048    0.767 2.719  0.00655 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsNo Clearance     8.048     0.1243      1.79     36.19

Concordance= 0.672  (se = 0.049 )
Likelihood ratio test= 11.61  on 1 df,   p=7e-04
Wald test            = 7.39  on 1 df,   p=0.007
Score (logrank) test = 9.78  on 1 df,   p=0.002
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 8.05 (1.79-36.19); p = 0.007"
circ_data$PFS.Event <- factor(circ_data$PFS.Event, levels = c("FALSE", "TRUE"), labels = c("No Progression", "Progression"))
contingency_table <- table(circ_data$ctDNA.Dynamics, circ_data$PFS.Event)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 7.2505, df = 1, p-value = 0.007088
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.005477
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
    1.796359 1833.444857
sample estimates:
odds ratio 
  27.59073 
print(contingency_table)
              
               No Progression Progression
  Clearance                 4           2
  No Clearance              1          18
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "ctDNA clearance post/under-treatment", 
       x = "ctDNA", 
       y = "Patients (%)", 
       fill = "Progression",
       caption = paste("Fisher's exact test p-value: ", format.pval(fisher_exact_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("No Progression" = "blue", "Progression" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Progression label size

#OS by ctDNA clearance post/during-ICI

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "NEGATIVE" ~ 1,
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "POSITIVE" ~ 2
  ))

survfit(Surv(time = circ_data$OS.months, event = circ_data$OS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$OS.months, event = circ_data$OS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

                  n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1  6      2     NA   20.50      NA
ctDNA.Dynamics=2 19     16   9.82    7.75    26.7
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(OS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$OS.months, event = circ_data$OS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="OS - ctDNA clearance Post/Under treatment", ylab= "Overall Survival", xlab="Months from Start of Immunotherapy", legend.labs=c("Clearance", "No Clearance"), legend.title="")

summary(KM_curve, times= c(0, 12, 24, 36))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0      6       0      1.0   0.000        1.000        1.000
   12      5       0      1.0   0.000           NA           NA
   24      2       2      0.6   0.219        0.126        0.882
   36      1       0      0.6   0.219        0.126        0.882

                ctDNA.Dynamics=2 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0     19       0    1.000  0.0000       1.0000        1.000
   12      8      11    0.421  0.1133       0.2037        0.625
   24      3       4    0.189  0.0942       0.0503        0.396
   36      2       1    0.126  0.0813       0.0222        0.325
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 25, number of events= 18 

                             coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.DynamicsNo Clearance 1.6133    5.0196   0.7578 2.129   0.0333 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsNo Clearance      5.02     0.1992     1.137     22.17

Concordance= 0.65  (se = 0.047 )
Likelihood ratio test= 6.57  on 1 df,   p=0.01
Wald test            = 4.53  on 1 df,   p=0.03
Score (logrank) test = 5.52  on 1 df,   p=0.02
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 5.02 (1.14-22.17); p = 0.033"
circ_data$OS.Event <- factor(circ_data$OS.Event, levels = c("FALSE", "TRUE"), labels = c("Alive", "Deceased"))
contingency_table <- table(circ_data$ctDNA.Dynamics, circ_data$OS.Event)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 3.6032, df = 1, p-value = 0.05767
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.03241
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
   0.8988842 150.9697807
sample estimates:
odds ratio 
   9.34674 
print(contingency_table)
              
               Alive Deceased
  Clearance        4        2
  No Clearance     3       16
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "ctDNA clearance post/under-treatment", 
       x = "ctDNA", 
       y = "Patients (%)", 
       fill = "Vital Status",
       caption = paste("Fisher's exact test p-value: ", format.pval(fisher_exact_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Alive" = "blue", "Deceased" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Progression label size

#Association of ctDNA clearance post/during-ICI with BOR

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "NEGATIVE" ~ 1,
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "POSITIVE" ~ 2
  ))

circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
circ_data$RESIST <- factor(circ_data$RESIST, levels = c("CR", "PR", "SD", "PD"))
contingency_table <- table(circ_data$ctDNA.Dynamics, circ_data$RESIST)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test

data:  contingency_table
X-squared = 14.309, df = 3, p-value = 0.002513
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 0.001129
alternative hypothesis: two.sided
print(contingency_table)
              
               CR PR SD PD
  Clearance     3  3  0  0
  No Clearance  1  2  6 10
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "ctDNA clearance post/under-treatment", 
       x = "ctDNA", 
       y = "Patients (%)", 
       fill = "BOR",
       caption = paste("Fisher's exact test p-value: ", format.pval(fisher_exact_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("CR" = "blue", "PR" = "lightblue", "SD" = "orange", "PD" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Progression label size

#Multivariate cox regression for PFS

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "NEGATIVE" ~ 1,
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "POSITIVE" ~ 2
  ))

circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
circ_data$cStage <- factor(circ_data$cStage, levels = c("0-II", "III-IV"))
circ_data$CPS.Scorev2 <- factor(circ_data$CPS.Scorev2, levels = c("≥1", "<1"))
surv_object <- Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics + Age + cStage + CPS.Scorev2, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for PFS", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#Multivariate cox regression for PFS v2

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "NEGATIVE" ~ 1,
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "POSITIVE" ~ 2
  ))

circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
circ_data$Inclusion.status <- factor(circ_data$Inclusion.status, levels = c("Loco-regional", "Metastatic"))
circ_data$p16.status <- factor(circ_data$p16.status, levels = c("Negative", "Positive"))
circ_data$CPS.Scorev2 <- factor(circ_data$CPS.Scorev2, levels = c("≥1", "<1"))
surv_object <- Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics + Age + Inclusion.status + p16.status + CPS.Scorev2, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for PFS", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#Multivariate cox regression for PFS v3

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "NEGATIVE" ~ 1,
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "POSITIVE" ~ 2
  ))

circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
circ_data$Inclusion.status <- factor(circ_data$Inclusion.status, levels = c("Loco-regional", "Metastatic"))
circ_data$Location <- factor(circ_data$Location, levels = c("Oropharynx/Oral", "Larynx", "Unknown"))
circ_data$p16.status <- factor(circ_data$p16.status, levels = c("Negative", "Positive"))
circ_data$CPS.Scorev2 <- factor(circ_data$CPS.Scorev2, levels = c("≥1", "<1"))
surv_object <- Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics + Age + Inclusion.status + Location + p16.status + CPS.Scorev2, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for PFS", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#Univariate PFS cox regression for variables included in MVA

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]

circ_data$ctDNA.Dynamics <- NA
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "NEGATIVE" ~ 1,
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "POSITIVE" ~ 2
  ))
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance")) #univariate for ctDNA clearance post-treatment
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data)
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 25, number of events= 20 

                            coef exp(coef) se(coef)     z Pr(>|z|)   
ctDNA.DynamicsNo Clearance 2.085     8.048    0.767 2.719  0.00655 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsNo Clearance     8.048     0.1243      1.79     36.19

Concordance= 0.672  (se = 0.049 )
Likelihood ratio test= 11.61  on 1 df,   p=7e-04
Wald test            = 7.39  on 1 df,   p=0.007
Score (logrank) test = 9.78  on 1 df,   p=0.002
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 8.05 (1.79-36.19); p = 0.007"
rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
cox_fit <- coxph(surv_object ~ Age, data=circ_data) #univariate for age
summary(cox_fit)
Call:
coxph(formula = surv_object ~ Age, data = circ_data)

  n= 25, number of events= 20 

        coef exp(coef) se(coef)      z Pr(>|z|)
Age -0.02566   0.97467  0.02392 -1.073    0.283

    exp(coef) exp(-coef) lower .95 upper .95
Age    0.9747      1.026      0.93     1.021

Concordance= 0.512  (se = 0.079 )
Likelihood ratio test= 1.12  on 1 df,   p=0.3
Wald test            = 1.15  on 1 df,   p=0.3
Score (logrank) test = 1.16  on 1 df,   p=0.3
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 0.97 (0.93-1.02); p = 0.283"
rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
circ_data$cStage <- factor(circ_data$cStage, levels = c("0-II", "III-IV")) #univariate for Stage
cox_fit <- coxph(surv_object ~ cStage, data=circ_data)
summary(cox_fit)
Call:
coxph(formula = surv_object ~ cStage, data = circ_data)

  n= 25, number of events= 20 

               coef exp(coef) se(coef)    z Pr(>|z|)
cStageIII-IV 0.9241    2.5196   0.6372 1.45    0.147

             exp(coef) exp(-coef) lower .95 upper .95
cStageIII-IV      2.52     0.3969    0.7226     8.785

Concordance= 0.585  (se = 0.047 )
Likelihood ratio test= 2.55  on 1 df,   p=0.1
Wald test            = 2.1  on 1 df,   p=0.1
Score (logrank) test = 2.24  on 1 df,   p=0.1
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 2.52 (0.72-8.78); p = 0.147"
rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
circ_data$Inclusion.status <- factor(circ_data$Inclusion.status, levels = c("Loco-regional", "Metastatic")) #univariate for Stage/disease status
cox_fit <- coxph(surv_object ~ Inclusion.status, data=circ_data)
summary(cox_fit)
Call:
coxph(formula = surv_object ~ Inclusion.status, data = circ_data)

  n= 25, number of events= 20 

                              coef exp(coef) se(coef)      z Pr(>|z|)
Inclusion.statusMetastatic -0.1110    0.8949   0.4582 -0.242    0.809

                           exp(coef) exp(-coef) lower .95 upper .95
Inclusion.statusMetastatic    0.8949      1.117    0.3646     2.197

Concordance= 0.556  (se = 0.056 )
Likelihood ratio test= 0.06  on 1 df,   p=0.8
Wald test            = 0.06  on 1 df,   p=0.8
Score (logrank) test = 0.06  on 1 df,   p=0.8
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 0.89 (0.36-2.2); p = 0.809"
rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
circ_data$p16.status <- factor(circ_data$p16.status, levels = c("Negative", "Positive")) #univariate for p16 status
cox_fit <- coxph(surv_object ~ p16.status, data=circ_data)
summary(cox_fit)
Call:
coxph(formula = surv_object ~ p16.status, data = circ_data)

  n= 24, number of events= 20 
   (1 observation deleted due to missingness)

                     coef exp(coef) se(coef)    z Pr(>|z|)
p16.statusPositive 0.2431    1.2752   0.6402 0.38    0.704

                   exp(coef) exp(-coef) lower .95 upper .95
p16.statusPositive     1.275     0.7842    0.3636     4.472

Concordance= 0.491  (se = 0.027 )
Likelihood ratio test= 0.14  on 1 df,   p=0.7
Wald test            = 0.14  on 1 df,   p=0.7
Score (logrank) test = 0.14  on 1 df,   p=0.7
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 1.28 (0.36-4.47); p = 0.704"
rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
circ_data$Location <- factor(circ_data$Location, levels = c("Oropharynx/Oral", "Larynx", "Unknown")) #univariate for disease location
cox_fit <- coxph(surv_object ~ p16.status, data=circ_data)
Warning: Loglik converged before variable  2 ; coefficient may be infinite. 
summary(cox_fit)
Call:
coxph(formula = surv_object ~ p16.status, data = circ_data)

  n= 25, number of events= 20 

                         coef  exp(coef)   se(coef)      z Pr(>|z|)
p16.statusPositive  2.431e-01  1.275e+00  6.402e-01  0.380    0.704
p16.statusUnknown  -1.815e+01  1.309e-08  6.641e+03 -0.003    0.998

                   exp(coef) exp(-coef) lower .95 upper .95
p16.statusPositive 1.275e+00  7.842e-01    0.3636     4.472
p16.statusUnknown  1.309e-08  7.641e+07    0.0000       Inf

Concordance= 0.526  (se = 0.041 )
Likelihood ratio test= 3.49  on 2 df,   p=0.2
Wald test            = 0.14  on 2 df,   p=0.9
Score (logrank) test = 1.92  on 2 df,   p=0.4
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = -18.15 (0.78-76405588.46); p = 0.64"
rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
surv_object <-Surv(time = circ_data$PFS.months, event = circ_data$PFS.Event)
circ_data$CPS.Scorev2 <- factor(circ_data$CPS.Scorev2, levels = c("≥1", "<1")) #univariate for CPS score
cox_fit <- coxph(surv_object ~ CPS.Scorev2, data=circ_data)
summary(cox_fit)
Call:
coxph(formula = surv_object ~ CPS.Scorev2, data = circ_data)

  n= 25, number of events= 20 

                coef exp(coef) se(coef)     z Pr(>|z|)
CPS.Scorev2<1 0.3866    1.4720   0.4905 0.788    0.431

              exp(coef) exp(-coef) lower .95 upper .95
CPS.Scorev2<1     1.472     0.6793    0.5628      3.85

Concordance= 0.564  (se = 0.062 )
Likelihood ratio test= 0.59  on 1 df,   p=0.4
Wald test            = 0.62  on 1 df,   p=0.4
Score (logrank) test = 0.63  on 1 df,   p=0.4
cox_fit_summary <- summary(cox_fit)

#Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 1.47 (0.56-3.85); p = 0.431"

#Multivariate cox regression for OS

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "NEGATIVE" ~ 1,
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "POSITIVE" ~ 2
  ))

circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
circ_data$cStage <- factor(circ_data$cStage, levels = c("0-II", "III-IV"))
circ_data$CPS.Scorev2 <- factor(circ_data$CPS.Scorev2, levels = c("≥1", "<1"))
surv_object <- Surv(time = circ_data$OS.months, event = circ_data$OS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics + Age + cStage + CPS.Scorev2, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for OS", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#Multivariate cox regression for OS v2

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("EORTC HNSCC ICI Clinical Data.csv")
circ_data <- circ_data[circ_data$ctDNA.available=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Base!="",]
circ_data <- circ_data[circ_data$ctDNA.Base=="POSITIVE",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "NEGATIVE" ~ 1,
    ctDNA.Base == "POSITIVE" & ctDNA.postTx == "POSITIVE" ~ 2
  ))

circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
circ_data$Inclusion.status <- factor(circ_data$Inclusion.status, levels = c("Loco-regional", "Metastatic"))
circ_data$p16.status <- factor(circ_data$p16.status, levels = c("Negative", "Positive"))
circ_data$CPS.Scorev2 <- factor(circ_data$CPS.Scorev2, levels = c("≥1", "<1"))
surv_object <- Surv(time = circ_data$OS.months, event = circ_data$OS.Event)
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics + Age + Inclusion.status + p16.status + CPS.Scorev2, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for OS", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)
LS0tCnRpdGxlOiAiRU9SVEMgSE5TQ0MgSUNJIEhvbm9yZSBldCBhbF8wMjAzMjAyNSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpsaWJyYXJ5KHN3aW1wbG90KQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoZ3RhYmxlKQpsaWJyYXJ5KHJlYWRyKSAKbGlicmFyeShtb3NhaWMpCmxpYnJhcnkoZHBseXIpIApsaWJyYXJ5KHN1cnZpdmFsKSAKbGlicmFyeShzdXJ2bWluZXIpIApsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGNveHBoZikKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ3RzdW1tYXJ5KQpsaWJyYXJ5KGZsZXh0YWJsZSkKbGlicmFyeShwYXJhbWV0ZXJzKQpsaWJyYXJ5KGNhcikKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoRFQpCmxpYnJhcnkocFJPQykKbGlicmFyeShybXMpCgojY3RETkEgRGV0ZWN0aW9uIFJhdGVzIGJ5IFdpbmRvdyBhbmQgU3RhZ2VzCmBgYHtyfQojY3RETkEgYXQgQmFzZWxpbmUKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZSE9IiIsXQpjaXJjX2RhdGEkY3RETkEuQmFzZSA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkJhc2UsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNpcmNfZGF0YSA8LSBzdWJzZXQoY2lyY19kYXRhLCBjdEROQS5CYXNlICVpbiUgYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSkKY2lyY19kYXRhJFN0YWdlIDwtIGZhY3RvcihjaXJjX2RhdGEkU3RhZ2UsIGxldmVscz1jKCJPIiwiSSIsIklJIiwiSUlJIiwiSVYiKSkKcG9zaXRpdmVfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiLCBieT1saXN0KGNpcmNfZGF0YSRTdGFnZSksIEZVTj1zdW0pCnRvdGFsX2NvdW50c19ieV9zdGFnZSA8LSBhZ2dyZWdhdGUoY2lyY19kYXRhJGN0RE5BLkJhc2UsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPWxlbmd0aCkKY29tYmluZWRfZGF0YSA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gdG90YWxfY291bnRzX2J5X3N0YWdlJEdyb3VwLjEsCiAgVG90YWxfQ291bnQgPSB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCwKICBQb3NpdGl2ZV9Db3VudCA9IHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4LAogIFJhdGUgPSAocG9zaXRpdmVfY291bnRzX2J5X3N0YWdlJHggLyB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCikKY29tYmluZWRfZGF0YSRSYXRlIDwtIHNwcmludGYoIiUuMmYlJSIsIGNvbWJpbmVkX2RhdGEkUmF0ZSkKb3ZlcmFsbF90b3RhbF9jb3VudCA8LSBucm93KGNpcmNfZGF0YSkKb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCA8LSBucm93KGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiLF0pCm92ZXJhbGxfcG9zaXRpdml0eV9yYXRlIDwtIChvdmVyYWxsX3Bvc2l0aXZlX2NvdW50IC8gb3ZlcmFsbF90b3RhbF9jb3VudCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCm92ZXJhbGxfcm93IDwtIGRhdGEuZnJhbWUoCiAgU3RhZ2UgPSAiT3ZlcmFsbCIsCiAgVG90YWxfQ291bnQgPSBvdmVyYWxsX3RvdGFsX2NvdW50LAogIFBvc2l0aXZlX0NvdW50ID0gb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCwKICBSYXRlID0gc3ByaW50ZigiJS4yZiUlIiwgb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUpCikKY29tYmluZWRfZGF0YSA8LSByYmluZChjb21iaW5lZF9kYXRhLCBvdmVyYWxsX3JvdykKcHJpbnQoY29tYmluZWRfZGF0YSkKCiNjdEROQSBwb3N0LXRyZWF0bWVudApybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiRU9SVEMgSE5TQ0MgSUNJIENsaW5pY2FsIERhdGEuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuYXZhaWxhYmxlPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5wb3N0VHghPSIiLF0KY2lyY19kYXRhJGN0RE5BLnBvc3RUeCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLnBvc3RUeCwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSkKY2lyY19kYXRhJFN0YWdlIDwtIGZhY3RvcihjaXJjX2RhdGEkU3RhZ2UsIGxldmVscz1jKCJPIiwiSSIsIklJIiwiSUlJIiwiSVYiKSkKcG9zaXRpdmVfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEucG9zdFR4ID09ICJQT1NJVElWRSIsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPXN1bSkKdG90YWxfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEucG9zdFR4LCBieT1saXN0KGNpcmNfZGF0YSRTdGFnZSksIEZVTj1sZW5ndGgpCmNvbWJpbmVkX2RhdGEgPC0gZGF0YS5mcmFtZSgKICBTdGFnZSA9IHRvdGFsX2NvdW50c19ieV9zdGFnZSRHcm91cC4xLAogIFRvdGFsX0NvdW50ID0gdG90YWxfY291bnRzX2J5X3N0YWdlJHgsCiAgUG9zaXRpdmVfQ291bnQgPSBwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UkeCwKICBSYXRlID0gKHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4IC8gdG90YWxfY291bnRzX2J5X3N0YWdlJHgpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQopCmNvbWJpbmVkX2RhdGEkUmF0ZSA8LSBzcHJpbnRmKCIlLjJmJSUiLCBjb21iaW5lZF9kYXRhJFJhdGUpCm92ZXJhbGxfdG90YWxfY291bnQgPC0gbnJvdyhjaXJjX2RhdGEpCm92ZXJhbGxfcG9zaXRpdmVfY291bnQgPC0gbnJvdyhjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLnBvc3RUeCA9PSAiUE9TSVRJVkUiLF0pCm92ZXJhbGxfcG9zaXRpdml0eV9yYXRlIDwtIChvdmVyYWxsX3Bvc2l0aXZlX2NvdW50IC8gb3ZlcmFsbF90b3RhbF9jb3VudCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCm92ZXJhbGxfcm93IDwtIGRhdGEuZnJhbWUoCiAgU3RhZ2UgPSAiT3ZlcmFsbCIsCiAgVG90YWxfQ291bnQgPSBvdmVyYWxsX3RvdGFsX2NvdW50LAogIFBvc2l0aXZlX0NvdW50ID0gb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCwKICBSYXRlID0gc3ByaW50ZigiJS4yZiUlIiwgb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUpCikKY29tYmluZWRfZGF0YSA8LSByYmluZChjb21iaW5lZF9kYXRhLCBvdmVyYWxsX3JvdykKcHJpbnQoY29tYmluZWRfZGF0YSkKYGBgCgoKCiNPdmVydmlldyBwbG90CmBgYHtyfQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2xpbnN0YWdlIDwtIHJlYWQuY3N2KCJFT1JUQyBJQ0lfT1AuY3N2IikKY2xpbnN0YWdlX2RmIDwtIGFzLmRhdGEuZnJhbWUoY2xpbnN0YWdlKQoKIyBDcmVhdGluZyB0aGUgYmFzaWMgc3dpbW1lciBwbG90Cm9wbG90IDwtIHN3aW1tZXJfcGxvdChkZj1jbGluc3RhZ2VfZGYsCiAgICAgICAgICAgICAgICAgICAgICBpZD0nUGF0aWVudE5hbWUnLAogICAgICAgICAgICAgICAgICAgICAgZW5kPSdmdS5kaWZmLm1vbnRocycsCiAgICAgICAgICAgICAgICAgICAgICBmaWxsPSdncmF5JywKICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPS4wMSkKCiMgQWRkaW5nIHRoZW1lcyBhbmQgc2NhbGVzCm9wbG90IDwtIG9wbG90ICsgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKQpvcGxvdCA8LSBvcGxvdCArIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNDgsIGJ5ID0gMykpCm9wbG90IDwtIG9wbG90ICsgbGFicyh4ID0iUGF0aWVudHMiLCB5PSJNb250aHMgZnJvbSBJbW11bm90aGVyYXB5IFN0YXJ0IikKCiMgQWRkaW5nIHN3aW1tZXIgcG9pbnRzCm9wbG90X2V2MSA8LSBvcGxvdCArIHN3aW1tZXJfcG9pbnRzKGRmX3BvaW50cz1jbGluc3RhZ2VfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkPSdQYXRpZW50TmFtZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWU9J2RhdGUuZGlmZi5tb250aHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lX3NoYXBlID0nRXZlbnRfdHlwZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVfY29sID0gJ0V2ZW50JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT0zLjUsZmlsbD0nYmxhY2snKQojIE9wdGlvbmFsbHkgdW5jb21tZW50IGFuZCB1c2UgY29sPSdkYXJrZ3JlZW4nIGlmIG5lZWRlZAoKIyBBZGRpbmcgc2hhcGUgbWFudWFsIHNjYWxlCm9wbG90X2V2MS4xIDwtIG9wbG90X2V2MSArIGdncGxvdDI6OnNjYWxlX3NoYXBlX21hbnVhbChuYW1lPSJFdmVudF90eXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz1jKDEsMTYsNiw0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKCdjdEROQV9uZWcnLCdjdEROQV9wb3MnLCdJbWFnaW5nJywnRGVhdGgnKSkKCiMgRGlzcGxheSB0aGUgcGxvdApvcGxvdF9ldjEuMQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcGxvdF9ldjIgPC0gb3Bsb3RfZXYxLjEgKyBzd2ltbWVyX2xpbmVzKGRmX2xpbmVzPWNsaW5zdGFnZV9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZD0nUGF0aWVudE5hbWUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0PSdUeF9zdGFydC5tb250aHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZD0nVHhfZW5kLm1vbnRocycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZV9jb2w9J1R4X3R5cGUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9My41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVfYWxwaGEgPSAxLjApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wbG90X2V2MiA8LSBvcGxvdF9ldjIgKyBndWlkZXMobGluZXR5cGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wbG90X2V2MgpvcGxvdF9ldjIuMiA8LSBvcGxvdF9ldjIgKyBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iRXZlbnQiLHZhbHVlcz1jKCAib3JhbmdlIiwgImJsYWNrIiwgImJsYWNrIiwgImxpZ2h0Ymx1ZSIsICJncmVlbiIsICJyZWQiKSkKb3Bsb3RfZXYyLjIKYGBgCgojT3ZlcnZpZXcgcGxvdCAtIHN0cmF0aWZpZWQgYnkgQk9SCmBgYHtyfQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2xpbnN0YWdlIDwtIHJlYWQuY3N2KCJFT1JUQyBJQ0lfT1AuY3N2IikKY2xpbnN0YWdlX2RmIDwtIGFzLmRhdGEuZnJhbWUoY2xpbnN0YWdlKQoKIyBDcmVhdGluZyB0aGUgYmFzaWMgc3dpbW1lciBwbG90Cm9wbG90X3N0cmF0aWZ5IDwtc3dpbW1lcl9wbG90KGRmPWNsaW5zdGFnZV9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQ9J1BhdGllbnROYW1lJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kPSdmdS5kaWZmLm1vbnRocycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbD0iZ3JheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhPTAuNzUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPS4wMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZV9zaXplID0gMTQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmF0aWZ5PSBjKCdSRUNJU1QnKSkKb3Bsb3Rfc3RyYXRpZnkgPC0gb3Bsb3Rfc3RyYXRpZnkgKyB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCkpCm9wbG90X3N0cmF0aWZ5IDwtIG9wbG90X3N0cmF0aWZ5ICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA0MiwgYnkgPSAzKSkKb3Bsb3Rfc3RyYXRpZnkgPC0gb3Bsb3Rfc3RyYXRpZnkgKyBsYWJzKHggPSJQYXRpZW50cyIgLCB5PSJNb250aHMgZnJvbSBJbW11bm90aGVyYXB5IFN0YXJ0IikKCiMgQWRkaW5nIHN3aW1tZXIgcG9pbnRzCm9wbG90X2V2MSA8LSBvcGxvdF9zdHJhdGlmeSArIHN3aW1tZXJfcG9pbnRzKGRmX3BvaW50cz1jbGluc3RhZ2VfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkPSdQYXRpZW50TmFtZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWU9J2RhdGUuZGlmZi5tb250aHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lX3NoYXBlID0nRXZlbnRfdHlwZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVfY29sID0gJ0V2ZW50JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT0zLjUsZmlsbD0nYmxhY2snKQojIE9wdGlvbmFsbHkgdW5jb21tZW50IGFuZCB1c2UgY29sPSdkYXJrZ3JlZW4nIGlmIG5lZWRlZAoKIyBBZGRpbmcgc2hhcGUgbWFudWFsIHNjYWxlCm9wbG90X2V2MS4xIDwtIG9wbG90X2V2MSArIGdncGxvdDI6OnNjYWxlX3NoYXBlX21hbnVhbChuYW1lPSJFdmVudF90eXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcz1jKDEsMTYsNiw0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKCdjdEROQV9uZWcnLCdjdEROQV9wb3MnLCdJbWFnaW5nJywnRGVhdGgnKSkKCiMgRGlzcGxheSB0aGUgcGxvdApvcGxvdF9ldjEuMQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcGxvdF9ldjIgPC0gb3Bsb3RfZXYxLjEgKyBzd2ltbWVyX2xpbmVzKGRmX2xpbmVzPWNsaW5zdGFnZV9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZD0nUGF0aWVudE5hbWUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0PSdUeF9zdGFydC5tb250aHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZD0nVHhfZW5kLm1vbnRocycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZV9jb2w9J1R4X3R5cGUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemU9My41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVfYWxwaGEgPSAxLjApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wbG90X2V2MiA8LSBvcGxvdF9ldjIgKyBndWlkZXMobGluZXR5cGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNSwgY29sb3IgPSAiYmxhY2siKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wbG90X2V2MgpvcGxvdF9ldjIuMiA8LSBvcGxvdF9ldjIgKyBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iRXZlbnQiLHZhbHVlcz1jKCAib3JhbmdlIiwgImJsYWNrIiwgImJsYWNrIiwgImxpZ2h0Ymx1ZSIsICJncmVlbiIsICJyZWQiKSkKb3Bsb3RfZXYyLjIKYGBgCgojQXNzb2NpYXRpb24gb2YgQmFzZWxpbmUgY3RETkEgTVRNIGxldmVscyB3aXRoIGNsaW5pY29wYXRob2xvZ2ljYWwgZmFjdG9ycwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2UhPSIiLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgp0YWxseSh+Y1N0YWdlLCBkYXRhPWNpcmNfZGF0YSwgbWFyZ2lucyA9IFRSVUUpCmNpcmNfZGF0YSRjU3RhZ2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRjU3RhZ2UsIGxldmVscyA9IGMoIjAtSUkiLCJJSUktSVYiKSwgbGFiZWxzID0gYygiMC1JSSAobj03KSIsIklJSS1JViAobj0yMikiKSkKYm94cGxvdChjdEROQS5CYXNlLk1UTX5jU3RhZ2UsIGRhdGE9Y2lyY19kYXRhLCBtYWluPSJjdEROQSBwcmUtdHJlYXRtZW50IE1UTSAtIFN0YWdlIiwgeGxhYj0iU3RhZ2UiLCB5bGFiPSJNVE0vbUwiLCBjb2w9IndoaXRlIixib3JkZXI9ImJsYWNrIikKbTE8LXdpbGNveC50ZXN0KGN0RE5BLkJhc2UuTVRNIH4gY1N0YWdlLCBkYXRhPWNpcmNfZGF0YSwgbmEucm09VFJVRSwgZXhhY3Q9RkFMU0UsIGNvbmYuaW50PVRSVUUpCnByaW50KG0xKQoKdGFsbHkofkluY2x1c2lvbi5zdGF0dXMsIGRhdGE9Y2lyY19kYXRhLCBtYXJnaW5zID0gVFJVRSkKY2lyY19kYXRhJEluY2x1c2lvbi5zdGF0dXMgPC0gZmFjdG9yKGNpcmNfZGF0YSRJbmNsdXNpb24uc3RhdHVzLCBsZXZlbHMgPSBjKCJMb2NvLXJlZ2lvbmFsIiwiTWV0YXN0YXRpYyIpLCBsYWJlbHMgPSBjKCJMb2NvLXJlZ2lvbmFsIChuPTE4KSIsIk1ldGFzdGF0aWMgKG49MTEpIikpCmJveHBsb3QoY3RETkEuQmFzZS5NVE1+SW5jbHVzaW9uLnN0YXR1cywgZGF0YT1jaXJjX2RhdGEsIG1haW49ImN0RE5BIHByZS10cmVhdG1lbnQgTVRNIC0gRGlzZWFzZSBTdGF0dXMiLCB4bGFiPSJEaXNlYXNlIFN0YXR1cyIsIHlsYWI9Ik1UTS9tTCIsIGNvbD0id2hpdGUiLGJvcmRlcj0iYmxhY2siKQptMjwtd2lsY294LnRlc3QoY3RETkEuQmFzZS5NVE0gfiBJbmNsdXNpb24uc3RhdHVzLCBkYXRhPWNpcmNfZGF0YSwgbmEucm09VFJVRSwgZXhhY3Q9RkFMU0UsIGNvbmYuaW50PVRSVUUpCnByaW50KG0yKQoKdGFsbHkofmNULlN0YXR1cywgZGF0YT1jaXJjX2RhdGEsIG1hcmdpbnMgPSBUUlVFKQpjaXJjX2RhdGEkY1QuU3RhdHVzIDwtIGZhY3RvcihjaXJjX2RhdGEkY1QuU3RhdHVzLCBsZXZlbHMgPSBjKCJjVDAtVDIiLCJjVDMtVDQiKSwgbGFiZWxzID0gYygiY1QwLVQyIChuPTExKSIsImNUMy1UNCAobj0xNykiKSkKYm94cGxvdChjdEROQS5CYXNlLk1UTX5jVC5TdGF0dXMsIGRhdGE9Y2lyY19kYXRhLCBtYWluPSJjdEROQSBwcmUtdHJlYXRtZW50IE1UTSAtIGNUIHN0YXR1cyIsIHhsYWI9ImNUIHN0YXR1cyIsIHlsYWI9Ik1UTS9tTCIsIGNvbD0id2hpdGUiLGJvcmRlcj0iYmxhY2siKQptMzwtd2lsY294LnRlc3QoY3RETkEuQmFzZS5NVE0gfiBjVC5TdGF0dXMsIGRhdGE9Y2lyY19kYXRhLCBuYS5ybT1UUlVFLCBleGFjdD1GQUxTRSwgY29uZi5pbnQ9VFJVRSkKcHJpbnQobTMpCgp0YWxseSh+Y04uU3RhdHVzLCBkYXRhPWNpcmNfZGF0YSwgbWFyZ2lucyA9IFRSVUUpCmNpcmNfZGF0YSRjTi5TdGF0dXMgPC0gZmFjdG9yKGNpcmNfZGF0YSRjTi5TdGF0dXMsIGxldmVscyA9IGMoImNOMCIsImNOMS1OMyIpLCBsYWJlbHMgPSBjKCJjTjAgKG49MTIpIiwiY04xLU4zIChuPTE1KSIpKQpib3hwbG90KGN0RE5BLkJhc2UuTVRNfmNOLlN0YXR1cywgZGF0YT1jaXJjX2RhdGEsIG1haW49ImN0RE5BIHByZS10cmVhdG1lbnQgTVRNIC0gY04gc3RhdHVzIiwgeGxhYj0iY04gc3RhdHVzIiwgeWxhYj0iTVRNL21MIiwgY29sPSJ3aGl0ZSIsYm9yZGVyPSJibGFjayIpCm00PC13aWxjb3gudGVzdChjdEROQS5CYXNlLk1UTSB+IGNOLlN0YXR1cywgZGF0YT1jaXJjX2RhdGEsIG5hLnJtPVRSVUUsIGV4YWN0PUZBTFNFLCBjb25mLmludD1UUlVFKQpwcmludChtNCkKCnRhbGx5KH5wMTYuc3RhdHVzLCBkYXRhPWNpcmNfZGF0YSwgbWFyZ2lucyA9IFRSVUUpCmNpcmNfZGF0YSRwMTYuc3RhdHVzIDwtIGZhY3RvcihjaXJjX2RhdGEkcDE2LnN0YXR1cywgbGV2ZWxzID0gYygiTmVnYXRpdmUiLCJQb3NpdGl2ZSIpLCBsYWJlbHMgPSBjKCJwMTYgbmVnIChuPTI0KSIsInAxNiBwb3MgKG49NCkiKSkKYm94cGxvdChjdEROQS5CYXNlLk1UTX5wMTYuc3RhdHVzLCBkYXRhPWNpcmNfZGF0YSwgbWFpbj0iY3RETkEgcHJlLXRyZWF0bWVudCBNVE0gLSBwMTYgc3RhdHVzIiwgeGxhYj0icDE2IHN0YXR1cyIsIHlsYWI9Ik1UTS9tTCIsIGNvbD0id2hpdGUiLGJvcmRlcj0iYmxhY2siKQptNTwtd2lsY294LnRlc3QoY3RETkEuQmFzZS5NVE0gfiBwMTYuc3RhdHVzLCBkYXRhPWNpcmNfZGF0YSwgbmEucm09VFJVRSwgZXhhY3Q9RkFMU0UsIGNvbmYuaW50PVRSVUUpCnByaW50KG01KQpgYGAKCiNNZWRpYW4gTVRNL21MIGxldmVscyBmb3IgY3RETkEgcG9zaXRpdmUgcHRzIHByZS10cmVhdG1lbnQKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikgCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiRU9SVEMgSE5TQ0MgSUNJIENsaW5pY2FsIERhdGEuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuYXZhaWxhYmxlPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2U9PSJQT1NJVElWRSIsXQoKbWVkaWFuX2N0RE5BIDwtIG1lZGlhbihjaXJjX2RhdGEkY3RETkEuQmFzZS5NVE0sIG5hLnJtID0gVFJVRSkKcmFuZ2VfY3RETkEgPC0gcmFuZ2UoY2lyY19kYXRhJGN0RE5BLkJhc2UuTVRNLCBuYS5ybSA9IFRSVUUpCmNhdCgiTWVkaWFuIE1UTS9tTCBwb3N0LXRyZWF0bWVudDoiLCBtZWRpYW5fY3RETkEsICJcbiIpCmNhdCgiUmFuZ2UgTVRNL21MIHBvc3QtdHJlYXRtZW50OiIsIHJhbmdlX2N0RE5BWzFdLCAiLSIsIHJhbmdlX2N0RE5BWzJdLCAiXG4iKQpgYGAKCiNNZWRpYW4gTVRNL21MIGxldmVscyBmb3IgY3RETkEgcG9zaXRpdmUgcHRzIHBvc3QtdHJlYXRtZW50CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEucG9zdFR4IT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLnBvc3RUeD09IlBPU0lUSVZFIixdCgptZWRpYW5fY3RETkEgPC0gbWVkaWFuKGNpcmNfZGF0YSRjdEROQS5wb3N0VHguTVRNLCBuYS5ybSA9IFRSVUUpCnJhbmdlX2N0RE5BIDwtIHJhbmdlKGNpcmNfZGF0YSRjdEROQS5wb3N0VHguTVRNLCBuYS5ybSA9IFRSVUUpCmNhdCgiTWVkaWFuIE1UTS9tTCBwb3N0LXRyZWF0bWVudDoiLCBtZWRpYW5fY3RETkEsICJcbiIpCmNhdCgiUmFuZ2UgTVRNL21MIHBvc3QtdHJlYXRtZW50OiIsIHJhbmdlX2N0RE5BWzFdLCAiLSIsIHJhbmdlX2N0RE5BWzJdLCAiXG4iKQpgYGAKCiNNZWRpYW4gdGltZSBmcm9tIGVuZCB0cmVhdG1lbnQgdG8gcHJvZ3Jlc3Npb24gZm9yIGN0RE5BIG5lZ2F0aXZlIHB0cyBwb3N0LXRyZWF0bWVudApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLnBvc3RUeCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5wb3N0VHg9PSJORUdBVElWRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRQRlMuRXZlbnQ9PSJUUlVFIixdCgptZWRpYW5fUEZTIDwtIG1lZGlhbihjaXJjX2RhdGEkUEZTLm1vbnRocywgbmEucm0gPSBUUlVFKQpyYW5nZV9QRlMgPC0gcmFuZ2UoY2lyY19kYXRhJFBGUy5tb250aHMsIG5hLnJtID0gVFJVRSkKY2F0KCJNZWRpYW4gUEZTOiIsIG1lZGlhbl9QRlMsICJcbiIpCmNhdCgiUmFuZ2UgUEZTOiIsIHJhbmdlX1BGU1sxXSwgIi0iLCByYW5nZV9QRlNbMl0sICJcbiIpCmBgYAoKI1BGUyBieSBjdEROQSBzdGF0dXMgcG9zdC9kdXJpbmctSUNJCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEucG9zdFR4IT0iIixdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkUEZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkUEZTLkV2ZW50KX5jdEROQS5wb3N0VHgsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLnBvc3RUeCkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oUEZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRQRlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRQRlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS5wb3N0VHgsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IlBGUyAtIGN0RE5BIFBvc3QvVW5kZXIgdHJlYXRtZW50IiwgeWxhYj0gIlByb2dyZXNzaW9uLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJNb250aHMgZnJvbSBTdGFydCBvZiBJbW11bm90aGVyYXB5IiwgbGVnZW5kLmxhYnM9YygiY3RETkEgTmVnYXRpdmUiLCAiY3RETkEgUG9zaXRpdmUiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygwLCAxMiwgMjQsIDM2KSkKY2lyY19kYXRhJGN0RE5BLnBvc3RUeCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLnBvc3RUeCwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLnBvc3RUeCwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpIApzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKY2lyY19kYXRhJGN0RE5BLnBvc3RUeCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLnBvc3RUeCwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJFBGUy5FdmVudCA8LSBmYWN0b3IoY2lyY19kYXRhJFBGUy5FdmVudCwgbGV2ZWxzID0gYygiRkFMU0UiLCAiVFJVRSIpLCBsYWJlbHMgPSBjKCJObyBQcm9ncmVzc2lvbiIsICJQcm9ncmVzc2lvbiIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB0YWJsZShjaXJjX2RhdGEkY3RETkEucG9zdFR4LCBjaXJjX2RhdGEkUEZTLkV2ZW50KQpjaGlfc3F1YXJlX3Rlc3QgPC0gY2hpc3EudGVzdChjb250aW5nZW5jeV90YWJsZSkKcHJpbnQoY2hpX3NxdWFyZV90ZXN0KQpmaXNoZXJfZXhhY3RfdGVzdCA8LSBmaXNoZXIudGVzdChjb250aW5nZW5jeV90YWJsZSkKcHJpbnQoZmlzaGVyX2V4YWN0X3Rlc3QpCnByaW50KGNvbnRpbmdlbmN5X3RhYmxlKQp0YWJsZV9kZiA8LSBhcy5kYXRhLmZyYW1lKGNvbnRpbmdlbmN5X3RhYmxlKQp0YWJsZV9kZiRUb3RhbCA8LSBhdmUodGFibGVfZGYkRnJlcSwgdGFibGVfZGYkVmFyMSwgRlVOID0gc3VtKQp0YWJsZV9kZiRQZXJjZW50YWdlIDwtIHRhYmxlX2RmJEZyZXEgLyB0YWJsZV9kZiRUb3RhbAp0YWJsZV9kZiRNaWRkbGVQZXJjZW50YWdlIDwtIHRhYmxlX2RmJFBlcmNlbnRhZ2UgLyAyCmdncGxvdCh0YWJsZV9kZiwgYWVzKHggPSBWYXIxLCB5ID0gUGVyY2VudGFnZSwgZmlsbCA9IFZhcjIpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX3RleHQoYWVzKHkgPSBNaWRkbGVQZXJjZW50YWdlLCBsYWJlbCA9IEZyZXEpLCBwb3NpdGlvbiA9ICJzdGFjayIsIGNvbG9yID0gImJsYWNrIiwgdmp1c3QgPSAxLjUsIHNpemUgPSA3KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gImN0RE5BIHN0YXR1cyBwb3N0L3VuZGVyLXRyZWF0bWVudCIsIAogICAgICAgeCA9ICJjdEROQSIsIAogICAgICAgeSA9ICJQYXRpZW50cyAoJSkiLCAKICAgICAgIGZpbGwgPSAiUHJvZ3Jlc3Npb24iLAogICAgICAgY2FwdGlvbiA9IHBhc3RlKCJGaXNoZXIncyBleGFjdCB0ZXN0IHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKGZpc2hlcl9leGFjdF90ZXN0JHAudmFsdWUpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJObyBQcm9ncmVzc2lvbiIgPSAiYmx1ZSIsICJQcm9ncmVzc2lvbiIgPSAicmVkIikpICsgIyBkZWZpbmUgY3VzdG9tIGNvbG9ycwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLjUsIHNpemUgPSAxNCksICMgaW5jcmVhc2UgeC1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB4LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIGxhYmVsIHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikpICAjIGluY3JlYXNlIFByb2dyZXNzaW9uIGxhYmVsIHNpemUKYGBgCgojT1MgYnkgY3RETkEgc3RhdHVzIHBvc3QvZHVyaW5nLUlDSQpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLnBvc3RUeCE9IiIsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJE9TLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkT1MuRXZlbnQpfmN0RE5BLnBvc3RUeCwgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY3RETkEucG9zdFR4KSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbCA9IG4oKSwKICAgIEV2ZW50cyA9IHN1bShPUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkT1MubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRPUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLnBvc3RUeCwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iT1MgLSBjdEROQSBQb3N0L1VuZGVyIHRyZWF0bWVudCIsIHlsYWI9ICJPdmVyYWxsIFN1cnZpdmFsIiwgeGxhYj0iTW9udGhzIGZyb20gU3RhcnQgb2YgSW1tdW5vdGhlcmFweSIsIGxlZ2VuZC5sYWJzPWMoImN0RE5BIE5lZ2F0aXZlIiwgImN0RE5BIFBvc2l0aXZlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0LCAzNikpCmNpcmNfZGF0YSRjdEROQS5wb3N0VHggPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5wb3N0VHgsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5wb3N0VHgsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKI0V4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCmNpcmNfZGF0YSRjdEROQS5wb3N0VHggPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5wb3N0VHgsIGxldmVscyA9IGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIiksIGxhYmVscyA9IGMoIk5lZ2F0aXZlIiwgIlBvc2l0aXZlIikpCmNpcmNfZGF0YSRPUy5FdmVudCA8LSBmYWN0b3IoY2lyY19kYXRhJE9TLkV2ZW50LCBsZXZlbHMgPSBjKCJGQUxTRSIsICJUUlVFIiksIGxhYmVscyA9IGMoIkFsaXZlIiwgIkRlY2Vhc2VkIikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHRhYmxlKGNpcmNfZGF0YSRjdEROQS5wb3N0VHgsIGNpcmNfZGF0YSRPUy5FdmVudCkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNoaV9zcXVhcmVfdGVzdCkKZmlzaGVyX2V4YWN0X3Rlc3QgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGZpc2hlcl9leGFjdF90ZXN0KQpwcmludChjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYgPC0gYXMuZGF0YS5mcmFtZShjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYkVG90YWwgPC0gYXZlKHRhYmxlX2RmJEZyZXEsIHRhYmxlX2RmJFZhcjEsIEZVTiA9IHN1bSkKdGFibGVfZGYkUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRGcmVxIC8gdGFibGVfZGYkVG90YWwKdGFibGVfZGYkTWlkZGxlUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRQZXJjZW50YWdlIC8gMgpnZ3Bsb3QodGFibGVfZGYsIGFlcyh4ID0gVmFyMSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBWYXIyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyh5ID0gTWlkZGxlUGVyY2VudGFnZSwgbGFiZWwgPSBGcmVxKSwgcG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIsIHZqdXN0ID0gMS41LCBzaXplID0gNykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJjdEROQSBzdGF0dXMgcG9zdC91bmRlci10cmVhdG1lbnQiLCAKICAgICAgIHggPSAiY3RETkEiLCAKICAgICAgIHkgPSAiUGF0aWVudHMgKCUpIiwgCiAgICAgICBmaWxsID0gIkxpdmluZyBTdGF0dXMiLAogICAgICAgY2FwdGlvbiA9IHBhc3RlKCJGaXNoZXIncyBleGFjdCB0ZXN0IHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKGZpc2hlcl9leGFjdF90ZXN0JHAudmFsdWUpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJBbGl2ZSIgPSAiYmx1ZSIsICJEZWNlYXNlZCIgPSAicmVkIikpICsgIyBkZWZpbmUgY3VzdG9tIGNvbG9ycwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLjUsIHNpemUgPSAxNCksICMgaW5jcmVhc2UgeC1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB4LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIGxhYmVsIHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikpICAjIGluY3JlYXNlIFByb2dyZXNzaW9uIGxhYmVsIHNpemUKYGBgCgojQXNzb2NpYXRpb24gb2YgY3RETkEgc3RhdHVzIHBvc3QvZHVyaW5nLUlDSSB3aXRoIEJPUgpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJGN0RE5BLnBvc3RUeCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLnBvc3RUeCwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJFJFU0lTVCA8LSBmYWN0b3IoY2lyY19kYXRhJFJFU0lTVCwgbGV2ZWxzID0gYygiQ1IiLCAiUFIiLCAiU0QiLCAiUEQiKSkKY29udGluZ2VuY3lfdGFibGUgPC0gdGFibGUoY2lyY19kYXRhJGN0RE5BLnBvc3RUeCwgY2lyY19kYXRhJFJFU0lTVCkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNoaV9zcXVhcmVfdGVzdCkKZmlzaGVyX2V4YWN0X3Rlc3QgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGZpc2hlcl9leGFjdF90ZXN0KQpwcmludChjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYgPC0gYXMuZGF0YS5mcmFtZShjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYkVG90YWwgPC0gYXZlKHRhYmxlX2RmJEZyZXEsIHRhYmxlX2RmJFZhcjEsIEZVTiA9IHN1bSkKdGFibGVfZGYkUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRGcmVxIC8gdGFibGVfZGYkVG90YWwKdGFibGVfZGYkTWlkZGxlUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRQZXJjZW50YWdlIC8gMgpnZ3Bsb3QodGFibGVfZGYsIGFlcyh4ID0gVmFyMSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBWYXIyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyh5ID0gTWlkZGxlUGVyY2VudGFnZSwgbGFiZWwgPSBGcmVxKSwgcG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIsIHZqdXN0ID0gMS41LCBzaXplID0gNykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJjdEROQSBzdGF0dXMgcG9zdC91bmRlci10cmVhdG1lbnQiLCAKICAgICAgIHggPSAiY3RETkEiLCAKICAgICAgIHkgPSAiUGF0aWVudHMgKCUpIiwgCiAgICAgICBmaWxsID0gIkJPUiIsCiAgICAgICBjYXB0aW9uID0gcGFzdGUoIkZpc2hlcidzIGV4YWN0IHRlc3QgcC12YWx1ZTogIiwgZm9ybWF0LnB2YWwoZmlzaGVyX2V4YWN0X3Rlc3QkcC52YWx1ZSkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkNSIiA9ICJibHVlIiwgIlBSIiA9ICJsaWdodGJsdWUiLCAiU0QiID0gIm9yYW5nZSIsICJQRCIgPSAicmVkIikpICsgIyBkZWZpbmUgY3VzdG9tIGNvbG9ycwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLjUsIHNpemUgPSAxNCksICMgaW5jcmVhc2UgeC1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB4LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIGxhYmVsIHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikpICAjIGluY3JlYXNlIFByb2dyZXNzaW9uIGxhYmVsIHNpemUKYGBgCgojUEZTIGJ5IGN0RE5BIGtpbmV0aWNzIHBvc3QvZHVyaW5nLUlDSQpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJM6UY3RETkEhPSIiLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRQRlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRQRlMuRXZlbnQpfs6UY3RETkEsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KM6UY3RETkEpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKFBGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkUEZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkUEZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gzpRjdEROQSwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iUEZTIC0gY3RETkEgS2luZXRpY3MgUG9zdC9VbmRlciB0cmVhdG1lbnQiLCB5bGFiPSAiUHJvZ3Jlc3Npb24tRnJlZSBTdXJ2aXZhbCIsIHhsYWI9Ik1vbnRocyBmcm9tIFN0YXJ0IG9mIEltbXVub3RoZXJhcHkiLCBsZWdlbmQubGFicz1jKCJEZWNyZWFzZWQgzpRjdEROQSIsICJJbmNyZWFzZWQgzpRjdEROQSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDAsIDEyLCAyNCwgMzYpKQpjaXJjX2RhdGEkzpRjdEROQSA8LSBmYWN0b3IoY2lyY19kYXRhJM6UY3RETkEsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiDOlGN0RE5BLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkgCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiNFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgpjaXJjX2RhdGEkzpRjdEROQSA8LSBmYWN0b3IoY2lyY19kYXRhJM6UY3RETkEsIGxldmVscyA9IGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIiksIGxhYmVscyA9IGMoIkRlY3JlYXNlZCIsICJJbmNyZWFzZWQiKSkKY2lyY19kYXRhJFBGUy5FdmVudCA8LSBmYWN0b3IoY2lyY19kYXRhJFBGUy5FdmVudCwgbGV2ZWxzID0gYygiRkFMU0UiLCAiVFJVRSIpLCBsYWJlbHMgPSBjKCJObyBQcm9ncmVzc2lvbiIsICJQcm9ncmVzc2lvbiIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB0YWJsZShjaXJjX2RhdGEkzpRjdEROQSwgY2lyY19kYXRhJFBGUy5FdmVudCkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNoaV9zcXVhcmVfdGVzdCkKZmlzaGVyX2V4YWN0X3Rlc3QgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGZpc2hlcl9leGFjdF90ZXN0KQpwcmludChjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYgPC0gYXMuZGF0YS5mcmFtZShjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYkVG90YWwgPC0gYXZlKHRhYmxlX2RmJEZyZXEsIHRhYmxlX2RmJFZhcjEsIEZVTiA9IHN1bSkKdGFibGVfZGYkUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRGcmVxIC8gdGFibGVfZGYkVG90YWwKdGFibGVfZGYkTWlkZGxlUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRQZXJjZW50YWdlIC8gMgpnZ3Bsb3QodGFibGVfZGYsIGFlcyh4ID0gVmFyMSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBWYXIyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyh5ID0gTWlkZGxlUGVyY2VudGFnZSwgbGFiZWwgPSBGcmVxKSwgcG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIsIHZqdXN0ID0gMS41LCBzaXplID0gNykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJjdEROQSBraW5ldGljcyBwb3N0L3VuZGVyLXRyZWF0bWVudCIsIAogICAgICAgeCA9ICJjdEROQSIsIAogICAgICAgeSA9ICJQYXRpZW50cyAoJSkiLCAKICAgICAgIGZpbGwgPSAiUHJvZ3Jlc3Npb24iLAogICAgICAgY2FwdGlvbiA9IHBhc3RlKCJGaXNoZXIncyBleGFjdCB0ZXN0IHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKGZpc2hlcl9leGFjdF90ZXN0JHAudmFsdWUpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJObyBQcm9ncmVzc2lvbiIgPSAiYmx1ZSIsICJQcm9ncmVzc2lvbiIgPSAicmVkIikpICsgIyBkZWZpbmUgY3VzdG9tIGNvbG9ycwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLjUsIHNpemUgPSAxNCksICMgaW5jcmVhc2UgeC1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB4LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIGxhYmVsIHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikpICAjIGluY3JlYXNlIFByb2dyZXNzaW9uIGxhYmVsIHNpemUKYGBgCgojT1MgYnkgY3RETkEga2luZXRpY3MgcG9zdC9kdXJpbmctSUNJCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkzpRjdEROQSE9IiIsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJE9TLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkT1MuRXZlbnQpfs6UY3RETkEsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KM6UY3RETkEpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKE9TLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRPUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJE9TLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gzpRjdEROQSwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iT1MgLSBjdEROQSBLaW5ldGljcyBQb3N0L1VuZGVyIHRyZWF0bWVudCIsIHlsYWI9ICJPdmVyYWxsIFN1cnZpdmFsIiwgeGxhYj0iTW9udGhzIGZyb20gU3RhcnQgb2YgSW1tdW5vdGhlcmFweSIsIGxlZ2VuZC5sYWJzPWMoIkRlY3JlYXNlZCDOlGN0RE5BIiwgIkluY3JlYXNlZCDOlGN0RE5BIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMCwgMTIsIDI0LCAzNikpCmNpcmNfZGF0YSTOlGN0RE5BIDwtIGZhY3RvcihjaXJjX2RhdGEkzpRjdEROQSwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IM6UY3RETkEsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKI0V4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCmNpcmNfZGF0YSTOlGN0RE5BIDwtIGZhY3RvcihjaXJjX2RhdGEkzpRjdEROQSwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiRGVjcmVhc2VkIiwgIkluY3JlYXNlZCIpKQpjaXJjX2RhdGEkT1MuRXZlbnQgPC0gZmFjdG9yKGNpcmNfZGF0YSRPUy5FdmVudCwgbGV2ZWxzID0gYygiRkFMU0UiLCAiVFJVRSIpLCBsYWJlbHMgPSBjKCJBbGl2ZSIsICJEZWNlYXNlZCIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB0YWJsZShjaXJjX2RhdGEkzpRjdEROQSwgY2lyY19kYXRhJE9TLkV2ZW50KQpjaGlfc3F1YXJlX3Rlc3QgPC0gY2hpc3EudGVzdChjb250aW5nZW5jeV90YWJsZSkKcHJpbnQoY2hpX3NxdWFyZV90ZXN0KQpmaXNoZXJfZXhhY3RfdGVzdCA8LSBmaXNoZXIudGVzdChjb250aW5nZW5jeV90YWJsZSkKcHJpbnQoZmlzaGVyX2V4YWN0X3Rlc3QpCnByaW50KGNvbnRpbmdlbmN5X3RhYmxlKQp0YWJsZV9kZiA8LSBhcy5kYXRhLmZyYW1lKGNvbnRpbmdlbmN5X3RhYmxlKQp0YWJsZV9kZiRUb3RhbCA8LSBhdmUodGFibGVfZGYkRnJlcSwgdGFibGVfZGYkVmFyMSwgRlVOID0gc3VtKQp0YWJsZV9kZiRQZXJjZW50YWdlIDwtIHRhYmxlX2RmJEZyZXEgLyB0YWJsZV9kZiRUb3RhbAp0YWJsZV9kZiRNaWRkbGVQZXJjZW50YWdlIDwtIHRhYmxlX2RmJFBlcmNlbnRhZ2UgLyAyCmdncGxvdCh0YWJsZV9kZiwgYWVzKHggPSBWYXIxLCB5ID0gUGVyY2VudGFnZSwgZmlsbCA9IFZhcjIpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX3RleHQoYWVzKHkgPSBNaWRkbGVQZXJjZW50YWdlLCBsYWJlbCA9IEZyZXEpLCBwb3NpdGlvbiA9ICJzdGFjayIsIGNvbG9yID0gImJsYWNrIiwgdmp1c3QgPSAxLjUsIHNpemUgPSA3KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gImN0RE5BIGtpbmV0aWNzIHBvc3QvdW5kZXItdHJlYXRtZW50IiwgCiAgICAgICB4ID0gImN0RE5BIiwgCiAgICAgICB5ID0gIlBhdGllbnRzICglKSIsIAogICAgICAgZmlsbCA9ICJWaXRhbCBTdGF0dXMiLAogICAgICAgY2FwdGlvbiA9IHBhc3RlKCJGaXNoZXIncyBleGFjdCB0ZXN0IHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKGZpc2hlcl9leGFjdF90ZXN0JHAudmFsdWUpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJBbGl2ZSIgPSAiYmx1ZSIsICJEZWNlYXNlZCIgPSAicmVkIikpICsgIyBkZWZpbmUgY3VzdG9tIGNvbG9ycwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLjUsIHNpemUgPSAxNCksICMgaW5jcmVhc2UgeC1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB4LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIGxhYmVsIHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikpICAjIGluY3JlYXNlIFByb2dyZXNzaW9uIGxhYmVsIHNpemUKYGBgCgojQXNzb2NpYXRpb24gb2YgY3RETkEga2luZXRpY3MgcG9zdC9kdXJpbmctSUNJIHdpdGggQk9SCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkzpRjdEROQSE9IiIsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSTOlGN0RE5BIDwtIGZhY3RvcihjaXJjX2RhdGEkzpRjdEROQSwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiRGVjcmVhc2VkIiwgIkluY3JlYXNlZCIpKQpjaXJjX2RhdGEkUkVTSVNUIDwtIGZhY3RvcihjaXJjX2RhdGEkUkVTSVNULCBsZXZlbHMgPSBjKCJDUiIsICJQUiIsICJTRCIsICJQRCIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB0YWJsZShjaXJjX2RhdGEkzpRjdEROQSwgY2lyY19kYXRhJFJFU0lTVCkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNoaV9zcXVhcmVfdGVzdCkKZmlzaGVyX2V4YWN0X3Rlc3QgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGZpc2hlcl9leGFjdF90ZXN0KQpwcmludChjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYgPC0gYXMuZGF0YS5mcmFtZShjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYkVG90YWwgPC0gYXZlKHRhYmxlX2RmJEZyZXEsIHRhYmxlX2RmJFZhcjEsIEZVTiA9IHN1bSkKdGFibGVfZGYkUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRGcmVxIC8gdGFibGVfZGYkVG90YWwKdGFibGVfZGYkTWlkZGxlUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRQZXJjZW50YWdlIC8gMgpnZ3Bsb3QodGFibGVfZGYsIGFlcyh4ID0gVmFyMSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBWYXIyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyh5ID0gTWlkZGxlUGVyY2VudGFnZSwgbGFiZWwgPSBGcmVxKSwgcG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIsIHZqdXN0ID0gMS41LCBzaXplID0gNykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJjdEROQSBraW5ldGljcyBwb3N0L3VuZGVyLXRyZWF0bWVudCIsIAogICAgICAgeCA9ICJjdEROQSIsIAogICAgICAgeSA9ICJQYXRpZW50cyAoJSkiLCAKICAgICAgIGZpbGwgPSAiQk9SIiwKICAgICAgIGNhcHRpb24gPSBwYXN0ZSgiRmlzaGVyJ3MgZXhhY3QgdGVzdCBwLXZhbHVlOiAiLCBmb3JtYXQucHZhbChmaXNoZXJfZXhhY3RfdGVzdCRwLnZhbHVlKSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ1IiID0gImJsdWUiLCAiUFIiID0gImxpZ2h0Ymx1ZSIsICJTRCIgPSAib3JhbmdlIiwgIlBEIiA9ICJyZWQiKSkgKyAjIGRlZmluZSBjdXN0b20gY29sb3JzCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEuNSwgc2l6ZSA9IDE0KSwgIyBpbmNyZWFzZSB4LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHktYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHgtYXhpcyBsYWJlbCBzaXplCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSkgICMgaW5jcmVhc2UgUHJvZ3Jlc3Npb24gbGFiZWwgc2l6ZQpgYGAKCiNQRlMgYnkgY3RETkEgY2xlYXJhbmNlIHBvc3QvZHVyaW5nLUlDSQpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2UhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZT09IlBPU0lUSVZFIixdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIE5BICNmaXJzdCB3ZSBjcmVhdGUgdGhlIHZhcmlhYmxlIGZvciB0aGUgY3RETkEgJiBOQUMgY29tYmluYXRpb24sIGFuZCB3ZSBhc3NpZ24gdmFsdWVzCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGEgJT4lCiAgbXV0YXRlKGN0RE5BLkR5bmFtaWNzID0gY2FzZV93aGVuKAogICAgY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiICYgY3RETkEucG9zdFR4ID09ICJORUdBVElWRSIgfiAxLAogICAgY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiICYgY3RETkEucG9zdFR4ID09ICJQT1NJVElWRSIgfiAyCiAgKSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJFBGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJFBGUy5FdmVudCl+Y3RETkEuRHluYW1pY3MsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLkR5bmFtaWNzKSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbCA9IG4oKSwKICAgIEV2ZW50cyA9IHN1bShQRlMuRXZlbnQpLAogICAgRnJhY3Rpb24gPSBFdmVudHMgLyBuKCksCiAgICBQZXJjZW50YWdlID0gKEV2ZW50cyAvIG4oKSkgKiAxMDAKICApCnByaW50KGV2ZW50X3N1bW1hcnkpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJFBGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJFBGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwicmVkIiksIHRpdGxlPSJQRlMgLSBjdEROQSBjbGVhcmFuY2UgUG9zdC9VbmRlciB0cmVhdG1lbnQiLCB5bGFiPSAiUHJvZ3Jlc3Npb24tRnJlZSBTdXJ2aXZhbCIsIHhsYWI9Ik1vbnRocyBmcm9tIFN0YXJ0IG9mIEltbXVub3RoZXJhcHkiLCBsZWdlbmQubGFicz1jKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMCwgMTIsIDI0LCAzNikpCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiKSwgbGFiZWxzID0gYygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgpjaXJjX2RhdGEkUEZTLkV2ZW50IDwtIGZhY3RvcihjaXJjX2RhdGEkUEZTLkV2ZW50LCBsZXZlbHMgPSBjKCJGQUxTRSIsICJUUlVFIiksIGxhYmVscyA9IGMoIk5vIFByb2dyZXNzaW9uIiwgIlByb2dyZXNzaW9uIikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHRhYmxlKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcywgY2lyY19kYXRhJFBGUy5FdmVudCkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNoaV9zcXVhcmVfdGVzdCkKZmlzaGVyX2V4YWN0X3Rlc3QgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGZpc2hlcl9leGFjdF90ZXN0KQpwcmludChjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYgPC0gYXMuZGF0YS5mcmFtZShjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYkVG90YWwgPC0gYXZlKHRhYmxlX2RmJEZyZXEsIHRhYmxlX2RmJFZhcjEsIEZVTiA9IHN1bSkKdGFibGVfZGYkUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRGcmVxIC8gdGFibGVfZGYkVG90YWwKdGFibGVfZGYkTWlkZGxlUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRQZXJjZW50YWdlIC8gMgpnZ3Bsb3QodGFibGVfZGYsIGFlcyh4ID0gVmFyMSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBWYXIyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyh5ID0gTWlkZGxlUGVyY2VudGFnZSwgbGFiZWwgPSBGcmVxKSwgcG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIsIHZqdXN0ID0gMS41LCBzaXplID0gNykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJjdEROQSBjbGVhcmFuY2UgcG9zdC91bmRlci10cmVhdG1lbnQiLCAKICAgICAgIHggPSAiY3RETkEiLCAKICAgICAgIHkgPSAiUGF0aWVudHMgKCUpIiwgCiAgICAgICBmaWxsID0gIlByb2dyZXNzaW9uIiwKICAgICAgIGNhcHRpb24gPSBwYXN0ZSgiRmlzaGVyJ3MgZXhhY3QgdGVzdCBwLXZhbHVlOiAiLCBmb3JtYXQucHZhbChmaXNoZXJfZXhhY3RfdGVzdCRwLnZhbHVlKSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8gUHJvZ3Jlc3Npb24iID0gImJsdWUiLCAiUHJvZ3Jlc3Npb24iID0gInJlZCIpKSArICMgZGVmaW5lIGN1c3RvbSBjb2xvcnMKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMS41LCBzaXplID0gMTQpLCAjIGluY3JlYXNlIHgtYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeC1heGlzIGxhYmVsIHNpemUKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHktYXhpcyBsYWJlbCBzaXplCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpKSAgIyBpbmNyZWFzZSBQcm9ncmVzc2lvbiBsYWJlbCBzaXplCmBgYAoKI09TIGJ5IGN0RE5BIGNsZWFyYW5jZSBwb3N0L2R1cmluZy1JQ0kKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikgCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiRU9SVEMgSE5TQ0MgSUNJIENsaW5pY2FsIERhdGEuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuYXZhaWxhYmxlPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2U9PSJQT1NJVElWRSIsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBOQSAjZmlyc3Qgd2UgY3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGN0RE5BICYgTkFDIGNvbWJpbmF0aW9uLCBhbmQgd2UgYXNzaWduIHZhbHVlcwpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5EeW5hbWljcyA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLkJhc2UgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLnBvc3RUeCA9PSAiTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLkJhc2UgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLnBvc3RUeCA9PSAiUE9TSVRJVkUiIH4gMgogICkpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRPUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJE9TLkV2ZW50KX5jdEROQS5EeW5hbWljcywgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY3RETkEuRHluYW1pY3MpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKE9TLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRPUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJE9TLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9Ik9TIC0gY3RETkEgY2xlYXJhbmNlIFBvc3QvVW5kZXIgdHJlYXRtZW50IiwgeWxhYj0gIk92ZXJhbGwgU3Vydml2YWwiLCB4bGFiPSJNb250aHMgZnJvbSBTdGFydCBvZiBJbW11bm90aGVyYXB5IiwgbGVnZW5kLmxhYnM9YygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDAsIDEyLCAyNCwgMzYpKQpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcywgbGV2ZWxzPWMoIjEiLCIyIiksIGxhYmVscyA9IGMoIkNsZWFyYW5jZSIsICJObyBDbGVhcmFuY2UiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkgCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKY2lyY19kYXRhJE9TLkV2ZW50IDwtIGZhY3RvcihjaXJjX2RhdGEkT1MuRXZlbnQsIGxldmVscyA9IGMoIkZBTFNFIiwgIlRSVUUiKSwgbGFiZWxzID0gYygiQWxpdmUiLCAiRGVjZWFzZWQiKSkKY29udGluZ2VuY3lfdGFibGUgPC0gdGFibGUoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBjaXJjX2RhdGEkT1MuRXZlbnQpCmNoaV9zcXVhcmVfdGVzdCA8LSBjaGlzcS50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChjaGlfc3F1YXJlX3Rlc3QpCmZpc2hlcl9leGFjdF90ZXN0IDwtIGZpc2hlci50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChmaXNoZXJfZXhhY3RfdGVzdCkKcHJpbnQoY29udGluZ2VuY3lfdGFibGUpCnRhYmxlX2RmIDwtIGFzLmRhdGEuZnJhbWUoY29udGluZ2VuY3lfdGFibGUpCnRhYmxlX2RmJFRvdGFsIDwtIGF2ZSh0YWJsZV9kZiRGcmVxLCB0YWJsZV9kZiRWYXIxLCBGVU4gPSBzdW0pCnRhYmxlX2RmJFBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkRnJlcSAvIHRhYmxlX2RmJFRvdGFsCnRhYmxlX2RmJE1pZGRsZVBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkUGVyY2VudGFnZSAvIDIKZ2dwbG90KHRhYmxlX2RmLCBhZXMoeCA9IFZhcjEsIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gVmFyMikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMoeSA9IE1pZGRsZVBlcmNlbnRhZ2UsIGxhYmVsID0gRnJlcSksIHBvc2l0aW9uID0gInN0YWNrIiwgY29sb3IgPSAiYmxhY2siLCB2anVzdCA9IDEuNSwgc2l6ZSA9IDcpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiY3RETkEgY2xlYXJhbmNlIHBvc3QvdW5kZXItdHJlYXRtZW50IiwgCiAgICAgICB4ID0gImN0RE5BIiwgCiAgICAgICB5ID0gIlBhdGllbnRzICglKSIsIAogICAgICAgZmlsbCA9ICJWaXRhbCBTdGF0dXMiLAogICAgICAgY2FwdGlvbiA9IHBhc3RlKCJGaXNoZXIncyBleGFjdCB0ZXN0IHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKGZpc2hlcl9leGFjdF90ZXN0JHAudmFsdWUpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJBbGl2ZSIgPSAiYmx1ZSIsICJEZWNlYXNlZCIgPSAicmVkIikpICsgIyBkZWZpbmUgY3VzdG9tIGNvbG9ycwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLjUsIHNpemUgPSAxNCksICMgaW5jcmVhc2UgeC1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB4LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIGxhYmVsIHNpemUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIikpICAjIGluY3JlYXNlIFByb2dyZXNzaW9uIGxhYmVsIHNpemUKYGBgCgojQXNzb2NpYXRpb24gb2YgY3RETkEgY2xlYXJhbmNlIHBvc3QvZHVyaW5nLUlDSSB3aXRoIEJPUgpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2UhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZT09IlBPU0lUSVZFIixdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIE5BICNmaXJzdCB3ZSBjcmVhdGUgdGhlIHZhcmlhYmxlIGZvciB0aGUgY3RETkEgJiBOQUMgY29tYmluYXRpb24sIGFuZCB3ZSBhc3NpZ24gdmFsdWVzCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGEgJT4lCiAgbXV0YXRlKGN0RE5BLkR5bmFtaWNzID0gY2FzZV93aGVuKAogICAgY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiICYgY3RETkEucG9zdFR4ID09ICJORUdBVElWRSIgfiAxLAogICAgY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiICYgY3RETkEucG9zdFR4ID09ICJQT1NJVElWRSIgfiAyCiAgKSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiKSwgbGFiZWxzID0gYygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpKQpjaXJjX2RhdGEkUkVTSVNUIDwtIGZhY3RvcihjaXJjX2RhdGEkUkVTSVNULCBsZXZlbHMgPSBjKCJDUiIsICJQUiIsICJTRCIsICJQRCIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB0YWJsZShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGNpcmNfZGF0YSRSRVNJU1QpCmNoaV9zcXVhcmVfdGVzdCA8LSBjaGlzcS50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChjaGlfc3F1YXJlX3Rlc3QpCmZpc2hlcl9leGFjdF90ZXN0IDwtIGZpc2hlci50ZXN0KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChmaXNoZXJfZXhhY3RfdGVzdCkKcHJpbnQoY29udGluZ2VuY3lfdGFibGUpCnRhYmxlX2RmIDwtIGFzLmRhdGEuZnJhbWUoY29udGluZ2VuY3lfdGFibGUpCnRhYmxlX2RmJFRvdGFsIDwtIGF2ZSh0YWJsZV9kZiRGcmVxLCB0YWJsZV9kZiRWYXIxLCBGVU4gPSBzdW0pCnRhYmxlX2RmJFBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkRnJlcSAvIHRhYmxlX2RmJFRvdGFsCnRhYmxlX2RmJE1pZGRsZVBlcmNlbnRhZ2UgPC0gdGFibGVfZGYkUGVyY2VudGFnZSAvIDIKZ2dwbG90KHRhYmxlX2RmLCBhZXMoeCA9IFZhcjEsIHkgPSBQZXJjZW50YWdlLCBmaWxsID0gVmFyMikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChhZXMoeSA9IE1pZGRsZVBlcmNlbnRhZ2UsIGxhYmVsID0gRnJlcSksIHBvc2l0aW9uID0gInN0YWNrIiwgY29sb3IgPSAiYmxhY2siLCB2anVzdCA9IDEuNSwgc2l6ZSA9IDcpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiY3RETkEgY2xlYXJhbmNlIHBvc3QvdW5kZXItdHJlYXRtZW50IiwgCiAgICAgICB4ID0gImN0RE5BIiwgCiAgICAgICB5ID0gIlBhdGllbnRzICglKSIsIAogICAgICAgZmlsbCA9ICJCT1IiLAogICAgICAgY2FwdGlvbiA9IHBhc3RlKCJGaXNoZXIncyBleGFjdCB0ZXN0IHAtdmFsdWU6ICIsIGZvcm1hdC5wdmFsKGZpc2hlcl9leGFjdF90ZXN0JHAudmFsdWUpKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJDUiIgPSAiYmx1ZSIsICJQUiIgPSAibGlnaHRibHVlIiwgIlNEIiA9ICJvcmFuZ2UiLCAiUEQiID0gInJlZCIpKSArICMgZGVmaW5lIGN1c3RvbSBjb2xvcnMKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMS41LCBzaXplID0gMTQpLCAjIGluY3JlYXNlIHgtYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeS1heGlzIHRleHQgc2l6ZQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICMgaW5jcmVhc2UgeC1heGlzIGxhYmVsIHNpemUKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHktYXhpcyBsYWJlbCBzaXplCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpKSAgIyBpbmNyZWFzZSBQcm9ncmVzc2lvbiBsYWJlbCBzaXplCmBgYAoKI011bHRpdmFyaWF0ZSBjb3ggcmVncmVzc2lvbiBmb3IgUEZTCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZSE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlPT0iUE9TSVRJVkUiLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gTkEgI2ZpcnN0IHdlIGNyZWF0ZSB0aGUgdmFyaWFibGUgZm9yIHRoZSBjdEROQSAmIE5BQyBjb21iaW5hdGlvbiwgYW5kIHdlIGFzc2lnbiB2YWx1ZXMKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBtdXRhdGUoY3RETkEuRHluYW1pY3MgPSBjYXNlX3doZW4oCiAgICBjdEROQS5CYXNlID09ICJQT1NJVElWRSIgJiBjdEROQS5wb3N0VHggPT0gIk5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5CYXNlID09ICJQT1NJVElWRSIgJiBjdEROQS5wb3N0VHggPT0gIlBPU0lUSVZFIiB+IDIKICApKQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIxIiwiMiIpLCBsYWJlbHMgPSBjKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIikpCmNpcmNfZGF0YSRjU3RhZ2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRjU3RhZ2UsIGxldmVscyA9IGMoIjAtSUkiLCAiSUlJLUlWIikpCmNpcmNfZGF0YSRDUFMuU2NvcmV2MiA8LSBmYWN0b3IoY2lyY19kYXRhJENQUy5TY29yZXYyLCBsZXZlbHMgPSBjKCLiiaUxIiwgIjwxIikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRQRlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRQRlMuRXZlbnQpIApjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MgKyBBZ2UgKyBjU3RhZ2UgKyBDUFMuU2NvcmV2MiwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LCBkYXRhID0gY2lyY19kYXRhLCBtYWluID0gIk11bHRpdmFyaWF0ZSBSZWdyZXNzaW9uIE1vZGVsIGZvciBQRlMiLCByZWZMYWJlbCA9ICJSZWZlcmVuY2UgR3JvdXAiKQp0ZXN0LnBoIDwtIGNveC56cGgoY294X2ZpdCkKYGBgCgoKI011bHRpdmFyaWF0ZSBjb3ggcmVncmVzc2lvbiBmb3IgUEZTIHYyCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZSE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlPT0iUE9TSVRJVkUiLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gTkEgI2ZpcnN0IHdlIGNyZWF0ZSB0aGUgdmFyaWFibGUgZm9yIHRoZSBjdEROQSAmIE5BQyBjb21iaW5hdGlvbiwgYW5kIHdlIGFzc2lnbiB2YWx1ZXMKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBtdXRhdGUoY3RETkEuRHluYW1pY3MgPSBjYXNlX3doZW4oCiAgICBjdEROQS5CYXNlID09ICJQT1NJVElWRSIgJiBjdEROQS5wb3N0VHggPT0gIk5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5CYXNlID09ICJQT1NJVElWRSIgJiBjdEROQS5wb3N0VHggPT0gIlBPU0lUSVZFIiB+IDIKICApKQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIxIiwiMiIpLCBsYWJlbHMgPSBjKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIikpCmNpcmNfZGF0YSRJbmNsdXNpb24uc3RhdHVzIDwtIGZhY3RvcihjaXJjX2RhdGEkSW5jbHVzaW9uLnN0YXR1cywgbGV2ZWxzID0gYygiTG9jby1yZWdpb25hbCIsICJNZXRhc3RhdGljIikpCmNpcmNfZGF0YSRwMTYuc3RhdHVzIDwtIGZhY3RvcihjaXJjX2RhdGEkcDE2LnN0YXR1cywgbGV2ZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJENQUy5TY29yZXYyIDwtIGZhY3RvcihjaXJjX2RhdGEkQ1BTLlNjb3JldjIsIGxldmVscyA9IGMoIuKJpTEiLCAiPDEiKSkKc3Vydl9vYmplY3QgPC0gU3Vydih0aW1lID0gY2lyY19kYXRhJFBGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJFBGUy5FdmVudCkgCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5EeW5hbWljcyArIEFnZSArIEluY2x1c2lvbi5zdGF0dXMgKyBwMTYuc3RhdHVzICsgQ1BTLlNjb3JldjIsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCwgZGF0YSA9IGNpcmNfZGF0YSwgbWFpbiA9ICJNdWx0aXZhcmlhdGUgUmVncmVzc2lvbiBNb2RlbCBmb3IgUEZTIiwgcmVmTGFiZWwgPSAiUmVmZXJlbmNlIEdyb3VwIikKdGVzdC5waCA8LSBjb3guenBoKGNveF9maXQpCmBgYAoKCiNNdWx0aXZhcmlhdGUgY294IHJlZ3Jlc3Npb24gZm9yIFBGUyB2MwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2UhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZT09IlBPU0lUSVZFIixdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIE5BICNmaXJzdCB3ZSBjcmVhdGUgdGhlIHZhcmlhYmxlIGZvciB0aGUgY3RETkEgJiBOQUMgY29tYmluYXRpb24sIGFuZCB3ZSBhc3NpZ24gdmFsdWVzCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGEgJT4lCiAgbXV0YXRlKGN0RE5BLkR5bmFtaWNzID0gY2FzZV93aGVuKAogICAgY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiICYgY3RETkEucG9zdFR4ID09ICJORUdBVElWRSIgfiAxLAogICAgY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiICYgY3RETkEucG9zdFR4ID09ICJQT1NJVElWRSIgfiAyCiAgKSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiKSwgbGFiZWxzID0gYygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpKQpjaXJjX2RhdGEkSW5jbHVzaW9uLnN0YXR1cyA8LSBmYWN0b3IoY2lyY19kYXRhJEluY2x1c2lvbi5zdGF0dXMsIGxldmVscyA9IGMoIkxvY28tcmVnaW9uYWwiLCAiTWV0YXN0YXRpYyIpKQpjaXJjX2RhdGEkTG9jYXRpb24gPC0gZmFjdG9yKGNpcmNfZGF0YSRMb2NhdGlvbiwgbGV2ZWxzID0gYygiT3JvcGhhcnlueC9PcmFsIiwgIkxhcnlueCIsICJVbmtub3duIikpCmNpcmNfZGF0YSRwMTYuc3RhdHVzIDwtIGZhY3RvcihjaXJjX2RhdGEkcDE2LnN0YXR1cywgbGV2ZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJENQUy5TY29yZXYyIDwtIGZhY3RvcihjaXJjX2RhdGEkQ1BTLlNjb3JldjIsIGxldmVscyA9IGMoIuKJpTEiLCAiPDEiKSkKc3Vydl9vYmplY3QgPC0gU3Vydih0aW1lID0gY2lyY19kYXRhJFBGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJFBGUy5FdmVudCkgCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5EeW5hbWljcyArIEFnZSArIEluY2x1c2lvbi5zdGF0dXMgKyBMb2NhdGlvbiArIHAxNi5zdGF0dXMgKyBDUFMuU2NvcmV2MiwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LCBkYXRhID0gY2lyY19kYXRhLCBtYWluID0gIk11bHRpdmFyaWF0ZSBSZWdyZXNzaW9uIE1vZGVsIGZvciBQRlMiLCByZWZMYWJlbCA9ICJSZWZlcmVuY2UgR3JvdXAiKQp0ZXN0LnBoIDwtIGNveC56cGgoY294X2ZpdCkKYGBgCgoKI1VuaXZhcmlhdGUgUEZTIGNveCByZWdyZXNzaW9uIGZvciB2YXJpYWJsZXMgaW5jbHVkZWQgaW4gTVZBCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZSE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlPT0iUE9TSVRJVkUiLF0KCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBOQQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5EeW5hbWljcyA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLkJhc2UgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLnBvc3RUeCA9PSAiTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLkJhc2UgPT0gIlBPU0lUSVZFIiAmIGN0RE5BLnBvc3RUeCA9PSAiUE9TSVRJVkUiIH4gMgogICkpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJFBGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJFBGUy5FdmVudCkKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIxIiwiMiIpLCBsYWJlbHMgPSBjKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIikpICN1bml2YXJpYXRlIGZvciBjdEROQSBjbGVhcmFuY2UgcG9zdC10cmVhdG1lbnQKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhPWNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKI0V4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikgCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiRU9SVEMgSE5TQ0MgSUNJIENsaW5pY2FsIERhdGEuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuYXZhaWxhYmxlPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2U9PSJQT1NJVElWRSIsXQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRQRlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRQRlMuRXZlbnQpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBBZ2UsIGRhdGE9Y2lyY19kYXRhKSAjdW5pdmFyaWF0ZSBmb3IgYWdlCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiNFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZSE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlPT0iUE9TSVRJVkUiLF0Kc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkUEZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkUEZTLkV2ZW50KQpjaXJjX2RhdGEkY1N0YWdlIDwtIGZhY3RvcihjaXJjX2RhdGEkY1N0YWdlLCBsZXZlbHMgPSBjKCIwLUlJIiwgIklJSS1JViIpKSAjdW5pdmFyaWF0ZSBmb3IgU3RhZ2UKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGNTdGFnZSwgZGF0YT1jaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiNFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZSE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlPT0iUE9TSVRJVkUiLF0Kc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkUEZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkUEZTLkV2ZW50KQpjaXJjX2RhdGEkSW5jbHVzaW9uLnN0YXR1cyA8LSBmYWN0b3IoY2lyY19kYXRhJEluY2x1c2lvbi5zdGF0dXMsIGxldmVscyA9IGMoIkxvY28tcmVnaW9uYWwiLCAiTWV0YXN0YXRpYyIpKSAjdW5pdmFyaWF0ZSBmb3IgU3RhZ2UvZGlzZWFzZSBzdGF0dXMKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IEluY2x1c2lvbi5zdGF0dXMsIGRhdGE9Y2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2UhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZT09IlBPU0lUSVZFIixdCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJFBGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJFBGUy5FdmVudCkKY2lyY19kYXRhJHAxNi5zdGF0dXMgPC0gZmFjdG9yKGNpcmNfZGF0YSRwMTYuc3RhdHVzLCBsZXZlbHMgPSBjKCJOZWdhdGl2ZSIsICJQb3NpdGl2ZSIpKSAjdW5pdmFyaWF0ZSBmb3IgcDE2IHN0YXR1cwpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gcDE2LnN0YXR1cywgZGF0YT1jaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiNFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZSE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlPT0iUE9TSVRJVkUiLF0Kc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkUEZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkUEZTLkV2ZW50KQpjaXJjX2RhdGEkTG9jYXRpb24gPC0gZmFjdG9yKGNpcmNfZGF0YSRMb2NhdGlvbiwgbGV2ZWxzID0gYygiT3JvcGhhcnlueC9PcmFsIiwgIkxhcnlueCIsICJVbmtub3duIikpICN1bml2YXJpYXRlIGZvciBkaXNlYXNlIGxvY2F0aW9uCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBwMTYuc3RhdHVzLCBkYXRhPWNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKI0V4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikgCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiRU9SVEMgSE5TQ0MgSUNJIENsaW5pY2FsIERhdGEuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuYXZhaWxhYmxlPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2U9PSJQT1NJVElWRSIsXQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRQRlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRQRlMuRXZlbnQpCmNpcmNfZGF0YSRDUFMuU2NvcmV2MiA8LSBmYWN0b3IoY2lyY19kYXRhJENQUy5TY29yZXYyLCBsZXZlbHMgPSBjKCLiiaUxIiwgIjwxIikpICN1bml2YXJpYXRlIGZvciBDUFMgc2NvcmUKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IENQUy5TY29yZXYyLCBkYXRhPWNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKI0V4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKYGBgCgojTXVsdGl2YXJpYXRlIGNveCByZWdyZXNzaW9uIGZvciBPUwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJFT1JUQyBITlNDQyBJQ0kgQ2xpbmljYWwgRGF0YS5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5hdmFpbGFibGU9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLkJhc2UhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZT09IlBPU0lUSVZFIixdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIE5BICNmaXJzdCB3ZSBjcmVhdGUgdGhlIHZhcmlhYmxlIGZvciB0aGUgY3RETkEgJiBOQUMgY29tYmluYXRpb24sIGFuZCB3ZSBhc3NpZ24gdmFsdWVzCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGEgJT4lCiAgbXV0YXRlKGN0RE5BLkR5bmFtaWNzID0gY2FzZV93aGVuKAogICAgY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiICYgY3RETkEucG9zdFR4ID09ICJORUdBVElWRSIgfiAxLAogICAgY3RETkEuQmFzZSA9PSAiUE9TSVRJVkUiICYgY3RETkEucG9zdFR4ID09ICJQT1NJVElWRSIgfiAyCiAgKSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiKSwgbGFiZWxzID0gYygiQ2xlYXJhbmNlIiwgIk5vIENsZWFyYW5jZSIpKQpjaXJjX2RhdGEkY1N0YWdlIDwtIGZhY3RvcihjaXJjX2RhdGEkY1N0YWdlLCBsZXZlbHMgPSBjKCIwLUlJIiwgIklJSS1JViIpKQpjaXJjX2RhdGEkQ1BTLlNjb3JldjIgPC0gZmFjdG9yKGNpcmNfZGF0YSRDUFMuU2NvcmV2MiwgbGV2ZWxzID0gYygi4omlMSIsICI8MSIpKQpzdXJ2X29iamVjdCA8LSBTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkT1MubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRPUy5FdmVudCkgCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5EeW5hbWljcyArIEFnZSArIGNTdGFnZSArIENQUy5TY29yZXYyLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsIGRhdGEgPSBjaXJjX2RhdGEsIG1haW4gPSAiTXVsdGl2YXJpYXRlIFJlZ3Jlc3Npb24gTW9kZWwgZm9yIE9TIiwgcmVmTGFiZWwgPSAiUmVmZXJlbmNlIEdyb3VwIikKdGVzdC5waCA8LSBjb3guenBoKGNveF9maXQpCmBgYAoKCiNNdWx0aXZhcmlhdGUgY294IHJlZ3Jlc3Npb24gZm9yIE9TIHYyCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkVPUlRDIEhOU0NDIElDSSBDbGluaWNhbCBEYXRhLmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmF2YWlsYWJsZT09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZSE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5CYXNlPT0iUE9TSVRJVkUiLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gTkEgI2ZpcnN0IHdlIGNyZWF0ZSB0aGUgdmFyaWFibGUgZm9yIHRoZSBjdEROQSAmIE5BQyBjb21iaW5hdGlvbiwgYW5kIHdlIGFzc2lnbiB2YWx1ZXMKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBtdXRhdGUoY3RETkEuRHluYW1pY3MgPSBjYXNlX3doZW4oCiAgICBjdEROQS5CYXNlID09ICJQT1NJVElWRSIgJiBjdEROQS5wb3N0VHggPT0gIk5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5CYXNlID09ICJQT1NJVElWRSIgJiBjdEROQS5wb3N0VHggPT0gIlBPU0lUSVZFIiB+IDIKICApKQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIxIiwiMiIpLCBsYWJlbHMgPSBjKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIikpCmNpcmNfZGF0YSRJbmNsdXNpb24uc3RhdHVzIDwtIGZhY3RvcihjaXJjX2RhdGEkSW5jbHVzaW9uLnN0YXR1cywgbGV2ZWxzID0gYygiTG9jby1yZWdpb25hbCIsICJNZXRhc3RhdGljIikpCmNpcmNfZGF0YSRwMTYuc3RhdHVzIDwtIGZhY3RvcihjaXJjX2RhdGEkcDE2LnN0YXR1cywgbGV2ZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJENQUy5TY29yZXYyIDwtIGZhY3RvcihjaXJjX2RhdGEkQ1BTLlNjb3JldjIsIGxldmVscyA9IGMoIuKJpTEiLCAiPDEiKSkKc3Vydl9vYmplY3QgPC0gU3Vydih0aW1lID0gY2lyY19kYXRhJE9TLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkT1MuRXZlbnQpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5EeW5hbWljcyArIEFnZSArIEluY2x1c2lvbi5zdGF0dXMgKyBwMTYuc3RhdHVzICsgQ1BTLlNjb3JldjIsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCwgZGF0YSA9IGNpcmNfZGF0YSwgbWFpbiA9ICJNdWx0aXZhcmlhdGUgUmVncmVzc2lvbiBNb2RlbCBmb3IgT1MiLCByZWZMYWJlbCA9ICJSZWZlcmVuY2UgR3JvdXAiKQp0ZXN0LnBoIDwtIGNveC56cGgoY294X2ZpdCkKYGBg